| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
# |
|
2
|
|
|
|
|
|
|
# Written by Travis Kent Beste |
|
3
|
|
|
|
|
|
|
# Mon Sep 13 10:49:23 CDT 2010 |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
package Insolation; |
|
6
|
|
|
|
|
|
|
|
|
7
|
1
|
|
|
1
|
|
22201
|
use 5.008000; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
28
|
|
|
8
|
1
|
|
|
1
|
|
5
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
60
|
|
|
9
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
5
|
|
|
|
1
|
|
|
|
|
24
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
1
|
|
|
1
|
|
389561
|
use Math::Trig; |
|
|
1
|
|
|
|
|
27408
|
|
|
|
1
|
|
|
|
|
13603
|
|
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
require Exporter; |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# Items to export into callers namespace by default. Note: do not export |
|
18
|
|
|
|
|
|
|
# names by default without a very good reason. Use EXPORT_OK instead. |
|
19
|
|
|
|
|
|
|
# Do not simply export all your public functions/methods/constants. |
|
20
|
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
# This allows declaration use Insolation ':all'; |
|
22
|
|
|
|
|
|
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK |
|
23
|
|
|
|
|
|
|
# will save memory. |
|
24
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( 'all' => [ qw( |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
) ] ); |
|
27
|
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
our @EXPORT = qw( |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
); |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
#----------------------------------------# |
|
37
|
|
|
|
|
|
|
# |
|
38
|
|
|
|
|
|
|
#----------------------------------------# |
|
39
|
|
|
|
|
|
|
sub new { |
|
40
|
0
|
|
|
0
|
0
|
|
my $class = shift; |
|
41
|
0
|
|
|
|
|
|
my %args = @_; |
|
42
|
|
|
|
|
|
|
|
|
43
|
0
|
|
|
|
|
|
my %fields = ( |
|
44
|
|
|
|
|
|
|
longitude => 0, |
|
45
|
|
|
|
|
|
|
latitude => 0, |
|
46
|
|
|
|
|
|
|
month => 0, |
|
47
|
|
|
|
|
|
|
_min_month => 0, |
|
48
|
|
|
|
|
|
|
_max_month => 0, |
|
49
|
|
|
|
|
|
|
year => 0, |
|
50
|
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# calculated data, hold it here while they decide how to output it |
|
52
|
|
|
|
|
|
|
data => {}, |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# calculated variables |
|
55
|
|
|
|
|
|
|
SCRATCH => { |
|
56
|
|
|
|
|
|
|
ECCEN => 0, # orbital parameter |
|
57
|
|
|
|
|
|
|
OBLIQ => 0, # orbital parameter |
|
58
|
|
|
|
|
|
|
OMEGVP => 0, # orbital parameter |
|
59
|
|
|
|
|
|
|
ITZONE => 0, # time zone |
|
60
|
|
|
|
|
|
|
}, |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# assign constants |
|
63
|
|
|
|
|
|
|
CONSTANTS => { |
|
64
|
|
|
|
|
|
|
PI => 4 * atan2(1, 1), # compute value of PI at run time - accurately |
|
65
|
|
|
|
|
|
|
TWOPI => (2 * (4 * atan2(1, 1))), # compute value of PI at run time - accurately |
|
66
|
|
|
|
|
|
|
RSUND => .267, # mean radius of Sun in degrees |
|
67
|
|
|
|
|
|
|
REFRAC => .583, # effective Sun disk increase |
|
68
|
|
|
|
|
|
|
EDAYZY => 365.2425, # actual length of a year - now |
|
69
|
|
|
|
|
|
|
DAYzMO => [31,28,31, 30,31,30, 31,31,30, 31,30,31], # days in each month - we calculate leap year below |
|
70
|
|
|
|
|
|
|
EARTH_WATT_M2 => 1367, # amount of energy that reaches the earth - watts/(m*m) |
|
71
|
|
|
|
|
|
|
}, |
|
72
|
|
|
|
|
|
|
); |
|
73
|
|
|
|
|
|
|
|
|
74
|
0
|
|
|
|
|
|
my $self = { |
|
75
|
|
|
|
|
|
|
%fields |
|
76
|
|
|
|
|
|
|
}; |
|
77
|
0
|
|
|
|
|
|
bless $self, $class; |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
#print Dumper $self; |
|
80
|
|
|
|
|
|
|
#exit; |
|
81
|
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
#--------------------# |
|
83
|
|
|
|
|
|
|
# validate input |
|
84
|
|
|
|
|
|
|
#--------------------# |
|
85
|
|
|
|
|
|
|
|
|
86
|
0
|
0
|
|
|
|
|
if (defined($args{'Longitude'})) { |
|
87
|
0
|
|
|
|
|
|
$self->set_longitude($args{Longitude}); |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
|
|
90
|
0
|
0
|
|
|
|
|
if (defined($args{'Latitude'})) { |
|
91
|
0
|
|
|
|
|
|
$self->set_latitude($args{Latitude}); |
|
92
|
|
|
|
|
|
|
} |
|
93
|
|
|
|
|
|
|
|
|
94
|
0
|
|
|
|
|
|
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); |
|
95
|
0
|
0
|
|
|
|
|
if (defined($args{'Month'})) { |
|
96
|
0
|
|
|
|
|
|
$self->set_month($args{Month}); |
|
97
|
|
|
|
|
|
|
} else { |
|
98
|
0
|
|
|
|
|
|
$self->{month} = -1; # will end up computing for all months |
|
99
|
0
|
|
|
|
|
|
$self->{_min_month} = 1; |
|
100
|
0
|
|
|
|
|
|
$self->{_max_month} = 12; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
0
|
0
|
|
|
|
|
if (defined($args{'Year'})) { |
|
104
|
0
|
|
|
|
|
|
$self->set_year($args{Year}); |
|
105
|
|
|
|
|
|
|
} else { |
|
106
|
0
|
|
|
|
|
|
$self->{year} = $year + 1900; # set default year to this year |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
|
return $self; |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
#----------------------------------------# |
|
113
|
|
|
|
|
|
|
# |
|
114
|
|
|
|
|
|
|
#----------------------------------------# |
|
115
|
|
|
|
|
|
|
sub DESTROY { |
|
116
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
117
|
|
|
|
|
|
|
|
|
118
|
0
|
0
|
|
|
|
|
$self->SUPER::DESTROY if $self->can("SUPER::DESTROY"); |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# Preloaded methods go here. |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
#----------------------------------------# |
|
124
|
|
|
|
|
|
|
# |
|
125
|
|
|
|
|
|
|
#----------------------------------------# |
|
126
|
|
|
|
|
|
|
sub set_year { |
|
127
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
128
|
0
|
|
|
|
|
|
my $year = shift; |
|
129
|
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
$self->{year} = sprintf("%d", $year); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
#----------------------------------------# |
|
134
|
|
|
|
|
|
|
# |
|
135
|
|
|
|
|
|
|
#----------------------------------------# |
|
136
|
|
|
|
|
|
|
sub set_month { |
|
137
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
138
|
0
|
|
|
|
|
|
my $month = shift; |
|
139
|
|
|
|
|
|
|
|
|
140
|
0
|
0
|
|
|
|
|
if ($self->isvalid_month($month)) { |
|
141
|
0
|
|
|
|
|
|
$self->{'month'} = sprintf("%d", $month); |
|
142
|
0
|
|
|
|
|
|
$self->{_min_month} = $self->{month}; |
|
143
|
0
|
|
|
|
|
|
$self->{_max_month} = $self->{month}; |
|
144
|
|
|
|
|
|
|
} else { |
|
145
|
0
|
|
|
|
|
|
print "error with month\n"; |
|
146
|
0
|
|
|
|
|
|
exit(1); |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
} |
|
149
|
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
#----------------------------------------# |
|
151
|
|
|
|
|
|
|
# |
|
152
|
|
|
|
|
|
|
#----------------------------------------# |
|
153
|
|
|
|
|
|
|
sub set_longitude { |
|
154
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
155
|
0
|
|
|
|
|
|
my $longitude = shift; |
|
156
|
|
|
|
|
|
|
|
|
157
|
0
|
0
|
|
|
|
|
if ($self->isvalid_longitude) { |
|
158
|
0
|
0
|
|
|
|
|
if ($self->isvalid_longitude($longitude)) { |
|
159
|
0
|
|
|
|
|
|
$self->{longitude} = $longitude; |
|
160
|
|
|
|
|
|
|
} else { |
|
161
|
0
|
|
|
|
|
|
print "error with longitude\n"; |
|
162
|
0
|
|
|
|
|
|
exit(1); |
|
163
|
|
|
|
|
|
|
} |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
#----------------------------------------# |
|
168
|
|
|
|
|
|
|
# |
|
169
|
|
|
|
|
|
|
#----------------------------------------# |
|
170
|
|
|
|
|
|
|
sub set_latitude { |
|
171
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
172
|
0
|
|
|
|
|
|
my $latitude = shift; |
|
173
|
|
|
|
|
|
|
|
|
174
|
0
|
0
|
|
|
|
|
if ($self->isvalid_latitude($latitude)) { |
|
175
|
0
|
|
|
|
|
|
$self->{latitude} = $latitude; |
|
176
|
|
|
|
|
|
|
} else { |
|
177
|
0
|
|
|
|
|
|
print "error with latitude\n"; |
|
178
|
0
|
|
|
|
|
|
exit(1); |
|
179
|
|
|
|
|
|
|
} |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
#----------------------------------------# |
|
183
|
|
|
|
|
|
|
# |
|
184
|
|
|
|
|
|
|
#----------------------------------------# |
|
185
|
|
|
|
|
|
|
sub isvalid_year { |
|
186
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
187
|
0
|
|
|
|
|
|
my $year = shift; |
|
188
|
|
|
|
|
|
|
|
|
189
|
0
|
0
|
0
|
|
|
|
if ( ($year >= 1) && ($year <= 9999) ) { |
|
190
|
0
|
|
|
|
|
|
return 1; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
0
|
|
|
|
|
|
return 0; |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
#----------------------------------------# |
|
197
|
|
|
|
|
|
|
# |
|
198
|
|
|
|
|
|
|
#----------------------------------------# |
|
199
|
|
|
|
|
|
|
sub isvalid_month { |
|
200
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
201
|
0
|
|
|
|
|
|
my $month = shift; |
|
202
|
|
|
|
|
|
|
|
|
203
|
0
|
0
|
|
|
|
|
if ($month eq "") { |
|
204
|
0
|
|
|
|
|
|
return 0; |
|
205
|
|
|
|
|
|
|
} |
|
206
|
|
|
|
|
|
|
|
|
207
|
0
|
0
|
0
|
|
|
|
if ( ($month >= 1) && ($month <= 12) ) { |
|
208
|
0
|
|
|
|
|
|
return 1; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
|
|
211
|
0
|
|
|
|
|
|
return 0; |
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
#----------------------------------------# |
|
215
|
|
|
|
|
|
|
# |
|
216
|
|
|
|
|
|
|
#----------------------------------------# |
|
217
|
|
|
|
|
|
|
sub isvalid_latitude { |
|
218
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
219
|
0
|
|
|
|
|
|
my $latitude = shift; |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
#print "$latitude\n"; |
|
222
|
|
|
|
|
|
|
|
|
223
|
0
|
0
|
|
|
|
|
if (abs($latitude) > 90) { |
|
224
|
0
|
|
|
|
|
|
return 0 |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
|
|
227
|
0
|
|
|
|
|
|
return 1; |
|
228
|
|
|
|
|
|
|
} |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
#----------------------------------------# |
|
231
|
|
|
|
|
|
|
# |
|
232
|
|
|
|
|
|
|
#----------------------------------------# |
|
233
|
|
|
|
|
|
|
sub isvalid_longitude { |
|
234
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
235
|
0
|
|
|
|
|
|
my $longitude = shift; |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
#print "$lonitude\n"; |
|
238
|
|
|
|
|
|
|
|
|
239
|
0
|
0
|
|
|
|
|
if ($self->{longitude} > 187.5) { |
|
240
|
0
|
|
|
|
|
|
$self->{longitude} = $self->{longitude} - 360; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
0
|
0
|
|
|
|
|
if ($self->{longitude} < -187.5) { |
|
243
|
0
|
|
|
|
|
|
$self->{longitude} = $self->{longitude} + 360; |
|
244
|
|
|
|
|
|
|
} |
|
245
|
0
|
0
|
|
|
|
|
if (abs($self->{longitude}) > 187.5) { |
|
246
|
0
|
|
|
|
|
|
return 0; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
|
|
249
|
0
|
|
|
|
|
|
return 1; |
|
250
|
|
|
|
|
|
|
} |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
#----------------------------------------# |
|
253
|
|
|
|
|
|
|
# calculate the data for the months given |
|
254
|
|
|
|
|
|
|
#----------------------------------------# |
|
255
|
|
|
|
|
|
|
sub calculate_insolation { |
|
256
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
257
|
|
|
|
|
|
|
|
|
258
|
0
|
|
|
|
|
|
$self->{SCRATCH}->{ITZONE} = int($self->{longitude} / 15); # Determine time zone |
|
259
|
0
|
|
|
|
|
|
$self->ORBPAR(); # Determine orbital parameters |
|
260
|
|
|
|
|
|
|
|
|
261
|
0
|
|
|
|
|
|
for (my $MONTH = $self->{_min_month}; $MONTH <= $self->{_max_month}; $MONTH++) { |
|
262
|
0
|
|
|
|
|
|
my $DATMAX = $self->{CONSTANTS}->{DAYzMO}[($MONTH - 1)]; # array indexed at zero instead of 1 |
|
263
|
0
|
0
|
0
|
|
|
|
if ( ($MONTH == 2) and ($self->QLEAPY($self->{year})) ) { |
|
264
|
0
|
|
|
|
|
|
$DATMAX = 29; |
|
265
|
|
|
|
|
|
|
} |
|
266
|
0
|
|
|
|
|
|
for (my $JDATE = 1; $JDATE <= $DATMAX; $JDATE++) { |
|
267
|
0
|
|
|
|
|
|
my $DATE = $JDATE-1 + .5 - $self->{longitude}/360; |
|
268
|
0
|
|
|
|
|
|
my $DAY = $self->YMDtoD($self->{year}, $MONTH, $DATE); |
|
269
|
|
|
|
|
|
|
#print "DAY : $DAY\n"; |
|
270
|
|
|
|
|
|
|
|
|
271
|
0
|
|
|
|
|
|
my ($SIND, $COSD, $SUNDIS, $SUNLON, $SUNLAT, $EQTIME) = $self->ORBIT($DAY); |
|
272
|
|
|
|
|
|
|
#print "SIND : $SIND\n"; |
|
273
|
|
|
|
|
|
|
#print "COSD : $COSD\n"; |
|
274
|
|
|
|
|
|
|
#print "SUNDIS : $SUNDIS\n"; |
|
275
|
|
|
|
|
|
|
#print "SUNLON : $SUNLON\n"; |
|
276
|
|
|
|
|
|
|
#print "SUNLAT : $SUNLAT\n"; |
|
277
|
|
|
|
|
|
|
#print "EQTIME : $EQTIME\n"; |
|
278
|
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
my ($COSZT, $COSZS) = $self->COSZIJ($SIND, $COSD); |
|
280
|
0
|
|
|
|
|
|
my $RSmEzM = ($self->{CONSTANTS}->{REFRAC} + $self->{CONSTANTS}->{RSUND} / $SUNDIS) * $self->{CONSTANTS}->{TWOPI}/360; |
|
281
|
0
|
|
|
|
|
|
my $DUSK = $self->SUNSET($SIND, $COSD, $RSmEzM); |
|
282
|
0
|
|
|
|
|
|
my $SRINC = $self->{CONSTANTS}->{EARTH_WATT_M2} * $COSZT / $SUNDIS**2; |
|
283
|
|
|
|
|
|
|
|
|
284
|
0
|
|
|
|
|
|
my ($dawn, $dusk); |
|
285
|
0
|
|
|
|
|
|
my $date = sprintf("%04d-%02d-%02d", $self->{year}, $MONTH, $JDATE); |
|
286
|
0
|
0
|
|
|
|
|
if ($DUSK >= 999999) { |
|
|
|
0
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
#--------------------# |
|
288
|
|
|
|
|
|
|
# Daylight at all times at this location on this day |
|
289
|
|
|
|
|
|
|
#--------------------# |
|
290
|
|
|
|
|
|
|
|
|
291
|
0
|
|
|
|
|
|
$dawn = 0; |
|
292
|
0
|
|
|
|
|
|
$dusk = 0; |
|
293
|
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
} elsif ($DUSK <= -999999) { |
|
295
|
|
|
|
|
|
|
#--------------------# |
|
296
|
|
|
|
|
|
|
# Nightime at all times at this location on this day |
|
297
|
|
|
|
|
|
|
#--------------------# |
|
298
|
|
|
|
|
|
|
|
|
299
|
0
|
|
|
|
|
|
$dawn = 0; |
|
300
|
0
|
|
|
|
|
|
$dusk = 0; |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
} else { |
|
303
|
|
|
|
|
|
|
#--------------------# |
|
304
|
|
|
|
|
|
|
# Daylight and nightime at this location on this day |
|
305
|
|
|
|
|
|
|
#--------------------# |
|
306
|
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
|
my $DAWN = (-$DUSK-$EQTIME) * 24 / $self->{CONSTANTS}->{TWOPI} + 12 - $self->{longitude} / 15 + $self->{SCRATCH}->{ITZONE}; |
|
308
|
0
|
|
|
|
|
|
$DUSK = ( $DUSK-$EQTIME) * 24 / $self->{CONSTANTS}->{TWOPI} + 12 - $self->{longitude} / 15 + $self->{SCRATCH}->{ITZONE}; |
|
309
|
0
|
|
|
|
|
|
my $IDAWNH = int($DAWN); |
|
310
|
0
|
|
|
|
|
|
my $IDUSKH = int($DUSK); |
|
311
|
0
|
|
|
|
|
|
my $IDAWNM = int( ($DAWN - $IDAWNH) * 60); |
|
312
|
0
|
|
|
|
|
|
my $IDUSKM = int( ($DUSK - $IDUSKH) * 60); |
|
313
|
0
|
|
|
|
|
|
$dawn = sprintf("%02d:%02d", $IDAWNH, $IDAWNM); |
|
314
|
0
|
|
|
|
|
|
$dusk = sprintf("%02d:%02d", $IDUSKH, $IDUSKM); |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
} |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
# set the data in the object's data collector - that way you can output it the way you'd like xml,csv,txt,etc |
|
319
|
0
|
|
|
|
|
|
$self->{data}->{'day'}->{$date}->{'data'} = { |
|
320
|
|
|
|
|
|
|
'dawn' => $dawn, |
|
321
|
|
|
|
|
|
|
'dusk' => $dusk, |
|
322
|
|
|
|
|
|
|
'srinc' => sprintf("%.45f", $SRINC), |
|
323
|
|
|
|
|
|
|
'coszs' => sprintf("%.45f", $COSZS), |
|
324
|
|
|
|
|
|
|
}; |
|
325
|
|
|
|
|
|
|
#printf "%10s - %5s - %5s - %.40f - %.40f\n", $date, $dawn, $dusk, $SRINC, $COSZS; |
|
326
|
|
|
|
|
|
|
} |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
} |
|
329
|
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
#----------------------------------------# |
|
331
|
|
|
|
|
|
|
# output in xml |
|
332
|
|
|
|
|
|
|
#----------------------------------------# |
|
333
|
|
|
|
|
|
|
sub get_xml { |
|
334
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
335
|
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
# only require if they use this method |
|
337
|
0
|
|
|
|
|
|
my $package = 'XML::Simple'; |
|
338
|
0
|
|
|
|
|
|
eval { |
|
339
|
0
|
|
|
|
|
|
(my $pkg = $package) =~ s|::|/|g; # require need a path |
|
340
|
0
|
|
|
|
|
|
require "$pkg.pm"; |
|
341
|
0
|
|
|
|
|
|
import $package; |
|
342
|
|
|
|
|
|
|
}; |
|
343
|
0
|
0
|
|
|
|
|
die $@ if( $@ ); |
|
344
|
|
|
|
|
|
|
|
|
345
|
0
|
|
|
|
|
|
my $xs = XML::Simple->new( |
|
346
|
|
|
|
|
|
|
AttrIndent => 1, |
|
347
|
|
|
|
|
|
|
RootName => 'Insolation', |
|
348
|
|
|
|
|
|
|
KeyAttr => [ 'date' => 'name'], |
|
349
|
|
|
|
|
|
|
NoAttr => 1, |
|
350
|
|
|
|
|
|
|
); |
|
351
|
|
|
|
|
|
|
|
|
352
|
0
|
|
|
|
|
|
my $xml = $xs->XMLout($self->{data}); |
|
353
|
|
|
|
|
|
|
#print "$xml"; |
|
354
|
|
|
|
|
|
|
|
|
355
|
0
|
|
|
|
|
|
return $xml; |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
#----------------------------------------# |
|
359
|
|
|
|
|
|
|
# output in csv |
|
360
|
|
|
|
|
|
|
#----------------------------------------# |
|
361
|
|
|
|
|
|
|
sub get_csv { |
|
362
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
363
|
0
|
|
|
|
|
|
my $csv; |
|
364
|
|
|
|
|
|
|
|
|
365
|
0
|
|
|
|
|
|
foreach my $date (sort keys %{$self->{data}->{day}}) { |
|
|
0
|
|
|
|
|
|
|
|
366
|
0
|
|
|
|
|
|
my $dawn = $self->{data}->{day}->{$date}->{data}->{dawn}; |
|
367
|
0
|
|
|
|
|
|
my $dusk = $self->{data}->{day}->{$date}->{data}->{dusk}; |
|
368
|
0
|
|
|
|
|
|
my $srinc = $self->{data}->{day}->{$date}->{data}->{srinc}; |
|
369
|
0
|
|
|
|
|
|
my $coszs = $self->{data}->{day}->{$date}->{data}->{coszs}; |
|
370
|
0
|
|
|
|
|
|
$csv .= sprintf("%s,%s,%s,%5.2f,%.4f\n", $date, $dawn, $dusk, $srinc, $coszs); |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
|
|
373
|
0
|
|
|
|
|
|
return $csv; |
|
374
|
|
|
|
|
|
|
} |
|
375
|
|
|
|
|
|
|
|
|
376
|
|
|
|
|
|
|
#----------------------------------------# |
|
377
|
|
|
|
|
|
|
# get the insolation for a computed value |
|
378
|
|
|
|
|
|
|
#----------------------------------------# |
|
379
|
|
|
|
|
|
|
sub get_ym_insolation { |
|
380
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
381
|
0
|
|
|
|
|
|
my $ym = shift; |
|
382
|
0
|
|
|
|
|
|
my $year = substr($ym, 0, 4); |
|
383
|
0
|
|
|
|
|
|
my $month = substr($ym, 5, 2); |
|
384
|
0
|
|
|
|
|
|
my $total = 0; |
|
385
|
|
|
|
|
|
|
|
|
386
|
0
|
0
|
|
|
|
|
if (! defined($self->{data}->{day}->{$ym . '-01'}->{data}->{srinc})) { |
|
387
|
0
|
|
|
|
|
|
print "front of the month doesn't exist...\n"; |
|
388
|
0
|
|
|
|
|
|
return 0; |
|
389
|
|
|
|
|
|
|
} else { |
|
390
|
|
|
|
|
|
|
#print "front of the month looks good...\n"; |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
|
|
393
|
0
|
|
|
|
|
|
my $DATMAX = $self->{CONSTANTS}->{DAYzMO}[($month - 1)]; # array indexed at zero instead of 1 |
|
394
|
0
|
0
|
0
|
|
|
|
if ( ($month == 2) and ($self->QLEAPY($year)) ) { |
|
395
|
0
|
|
|
|
|
|
$DATMAX = 29; |
|
396
|
|
|
|
|
|
|
} |
|
397
|
0
|
0
|
|
|
|
|
if (! defined($self->{data}->{day}->{$ym . '-' . $DATMAX}->{data}->{srinc})) { |
|
398
|
0
|
|
|
|
|
|
print "end of the month doesn't exist...\n"; |
|
399
|
0
|
|
|
|
|
|
return 0; |
|
400
|
|
|
|
|
|
|
} else { |
|
401
|
|
|
|
|
|
|
#print "end of the month looks good...\n"; |
|
402
|
|
|
|
|
|
|
} |
|
403
|
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
# compute the month total |
|
405
|
0
|
|
|
|
|
|
for(my $d = 1; $d <= $DATMAX; $d++) { |
|
406
|
0
|
|
|
|
|
|
$total += $self->{data}->{day}->{$ym . sprintf("-%02d", $d)}->{data}->{srinc}; |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
0
|
|
|
|
|
|
return $total; |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
#----------------------------------------# |
|
413
|
|
|
|
|
|
|
# get the insolation for a computed value |
|
414
|
|
|
|
|
|
|
#----------------------------------------# |
|
415
|
|
|
|
|
|
|
sub get_ymd_insolation { |
|
416
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
417
|
0
|
|
|
|
|
|
my $ymd = shift; |
|
418
|
|
|
|
|
|
|
|
|
419
|
0
|
0
|
|
|
|
|
if (! defined($self->{data}->{day}->{$ymd}->{data}->{srinc})) { |
|
420
|
0
|
|
|
|
|
|
return -1; |
|
421
|
|
|
|
|
|
|
} |
|
422
|
|
|
|
|
|
|
|
|
423
|
0
|
|
|
|
|
|
return $self->{data}->{day}->{$ymd}->{data}->{srinc}; |
|
424
|
|
|
|
|
|
|
} |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
#----------------------------------------# |
|
427
|
|
|
|
|
|
|
# ORBPAR calculates the three orbital parameters as a function of |
|
428
|
|
|
|
|
|
|
# YEAR. The source of these calculations is: Andre L. Berger, |
|
429
|
|
|
|
|
|
|
# 1978, "Long-Term Variations of Daily Insolation and Quaternary |
|
430
|
|
|
|
|
|
|
# Climatic Changes", JAS, v.35, p.2362. Also useful is: Andre L. |
|
431
|
|
|
|
|
|
|
# Berger, May 1978, "A Simple Algorithm to Compute Long Term |
|
432
|
|
|
|
|
|
|
# Variations of Daily Insolation", published by Institut |
|
433
|
|
|
|
|
|
|
# D'Astronomie de Geophysique, Universite Catholique de Louvain, |
|
434
|
|
|
|
|
|
|
# Louvain-la Neuve, No. 18. |
|
435
|
|
|
|
|
|
|
# |
|
436
|
|
|
|
|
|
|
# Tables and equations refer to the first reference (JAS). The |
|
437
|
|
|
|
|
|
|
# corresponding table or equation in the second reference is |
|
438
|
|
|
|
|
|
|
# enclosed in parentheses. The coefficients used in this |
|
439
|
|
|
|
|
|
|
# subroutine are slightly more precise than those used in either |
|
440
|
|
|
|
|
|
|
# of the references. The generated orbital parameters are precise |
|
441
|
|
|
|
|
|
|
# within plus or minus 1000000 years from present. |
|
442
|
|
|
|
|
|
|
# |
|
443
|
|
|
|
|
|
|
# Input: YEAR = years A.D. are positive, B.C. are negative |
|
444
|
|
|
|
|
|
|
# Output: ECCEN = ECCENtricity of orbital ellipse |
|
445
|
|
|
|
|
|
|
# OBLIQ = latitude of Tropic of Cancer in radians |
|
446
|
|
|
|
|
|
|
# OMEGVP = longitude of perihelion = |
|
447
|
|
|
|
|
|
|
# = spatial angle from vernal equinox to perihelion |
|
448
|
|
|
|
|
|
|
# in radians with sun as angle vertex |
|
449
|
|
|
|
|
|
|
#----------------------------------------# |
|
450
|
|
|
|
|
|
|
sub ORBPAR { |
|
451
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
452
|
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
# Table 1 (2). Obliquity relative to mean ecliptic of date: OBLIQD |
|
454
|
0
|
|
|
|
|
|
my @table1 = (-2462.2214466, 31.609974, 251.9025, |
|
455
|
|
|
|
|
|
|
-857.3232075, 32.620504, 280.8325, |
|
456
|
|
|
|
|
|
|
-629.3231835, 24.172203, 128.3057, |
|
457
|
|
|
|
|
|
|
-414.2804924, 31.983787, 292.7252, |
|
458
|
|
|
|
|
|
|
-311.7632587, 44.828336, 15.3747, |
|
459
|
|
|
|
|
|
|
308.9408604, 30.973257, 263.7951, |
|
460
|
|
|
|
|
|
|
-162.5533601, 43.668246, 308.4258, |
|
461
|
|
|
|
|
|
|
-116.1077911, 32.246691, 240.0099, |
|
462
|
|
|
|
|
|
|
101.1189923, 30.599444, 222.9725, |
|
463
|
|
|
|
|
|
|
-67.6856209, 42.681324, 268.7809, |
|
464
|
|
|
|
|
|
|
24.9079067, 43.836462, 316.7998, |
|
465
|
|
|
|
|
|
|
22.5811241, 47.439436, 319.6024, |
|
466
|
|
|
|
|
|
|
-21.1648355, 63.219948, 143.8050, |
|
467
|
|
|
|
|
|
|
-15.6549876, 64.230478, 172.7351, |
|
468
|
|
|
|
|
|
|
15.3936813, 1.010530, 28.9300, |
|
469
|
|
|
|
|
|
|
14.6660938, 7.437771, 123.5968, |
|
470
|
|
|
|
|
|
|
-11.7273029, 55.782177, 20.2082, |
|
471
|
|
|
|
|
|
|
10.2742696, .373813, 40.8226, |
|
472
|
|
|
|
|
|
|
6.4914588, 13.218362, 123.4722, |
|
473
|
|
|
|
|
|
|
5.8539148, 62.583231, 155.6977, |
|
474
|
|
|
|
|
|
|
-5.4872205, 63.593761, 184.6277, |
|
475
|
|
|
|
|
|
|
-5.4290191, 76.438310, 267.2772, |
|
476
|
|
|
|
|
|
|
5.1609570, 45.815258, 55.0196, |
|
477
|
|
|
|
|
|
|
5.0786314, 8.448301, 152.5268, |
|
478
|
|
|
|
|
|
|
-4.0735782, 56.792707, 49.1382, |
|
479
|
|
|
|
|
|
|
3.7227167, 49.747842, 204.6609, |
|
480
|
|
|
|
|
|
|
3.3971932, 12.058272, 56.5233, |
|
481
|
|
|
|
|
|
|
-2.8347004, 75.278220, 200.3284, |
|
482
|
|
|
|
|
|
|
-2.6550721, 65.241008, 201.6651, |
|
483
|
|
|
|
|
|
|
-2.5717867, 64.604291, 213.5577, |
|
484
|
|
|
|
|
|
|
-2.4712188, 1.647247, 17.0374, |
|
485
|
|
|
|
|
|
|
2.4625410, 7.811584, 164.4194, |
|
486
|
|
|
|
|
|
|
2.2464112, 12.207832, 94.5422, |
|
487
|
|
|
|
|
|
|
-2.0755511, 63.856665, 131.9124, |
|
488
|
|
|
|
|
|
|
-1.9713669, 56.155990, 61.0309, |
|
489
|
|
|
|
|
|
|
-1.8813061, 77.448840, 296.2073, |
|
490
|
|
|
|
|
|
|
-1.8468785, 6.801054, 135.4894, |
|
491
|
|
|
|
|
|
|
1.8186742, 62.209418, 114.8750, |
|
492
|
|
|
|
|
|
|
1.7601888, 20.656133, 247.0691, |
|
493
|
|
|
|
|
|
|
-1.5428851, 48.344406, 256.6114, |
|
494
|
|
|
|
|
|
|
1.4738838, 55.145460, 32.1008, |
|
495
|
|
|
|
|
|
|
-1.4593669, 69.000539, 143.6804, |
|
496
|
|
|
|
|
|
|
1.4192259, 11.071350, 16.8784, |
|
497
|
|
|
|
|
|
|
-1.1818980, 74.291298, 160.6835, |
|
498
|
|
|
|
|
|
|
1.1756474, 11.047742, 27.5932, |
|
499
|
|
|
|
|
|
|
-1.1316126, 0.636717, 348.1074, |
|
500
|
|
|
|
|
|
|
1.0896928, 12.844549, 82.6496 |
|
501
|
|
|
|
|
|
|
); |
|
502
|
|
|
|
|
|
|
#print Dumper \@table1; |
|
503
|
|
|
|
|
|
|
|
|
504
|
|
|
|
|
|
|
# Table 4 (1). Fundamental elements of the ecliptic: ECCEN sin(pi) |
|
505
|
0
|
|
|
|
|
|
my @table4 = ( .01860798, 4.207205, 28.620089, |
|
506
|
|
|
|
|
|
|
.01627522, 7.346091, 193.788772, |
|
507
|
|
|
|
|
|
|
-.01300660, 17.857263, 308.307024, |
|
508
|
|
|
|
|
|
|
.00988829, 17.220546, 320.199637, |
|
509
|
|
|
|
|
|
|
-.00336700, 16.846733, 279.376984, |
|
510
|
|
|
|
|
|
|
.00333077, 5.199079, 87.195000, |
|
511
|
|
|
|
|
|
|
-.00235400, 18.231076, 349.129677, |
|
512
|
|
|
|
|
|
|
.00140015, 26.216758, 128.443387, |
|
513
|
|
|
|
|
|
|
.00100700, 6.359169, 154.143880, |
|
514
|
|
|
|
|
|
|
.00085700, 16.210016, 291.269597, |
|
515
|
|
|
|
|
|
|
.00064990, 3.065181, 114.860583, |
|
516
|
|
|
|
|
|
|
.00059900, 16.583829, 332.092251, |
|
517
|
|
|
|
|
|
|
.00037800, 18.493980, 296.414411, |
|
518
|
|
|
|
|
|
|
-.00033700, 6.190953, 145.769910, |
|
519
|
|
|
|
|
|
|
.00027600, 18.867793, 337.237063, |
|
520
|
|
|
|
|
|
|
.00018200, 17.425567, 152.092288, |
|
521
|
|
|
|
|
|
|
-.00017400, 6.186001, 126.839891, |
|
522
|
|
|
|
|
|
|
-.00012400, 18.417441, 210.667199, |
|
523
|
|
|
|
|
|
|
.00001250, 0.667863, 72.108838 |
|
524
|
|
|
|
|
|
|
); |
|
525
|
|
|
|
|
|
|
#print Dumper \@table4; |
|
526
|
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# Table 5 (3). General precession in longitude: psi |
|
528
|
0
|
|
|
|
|
|
my @table5 = ( 7391.0225890, 31.609974, 251.9025, |
|
529
|
|
|
|
|
|
|
2555.1526947, 32.620504, 280.8325, |
|
530
|
|
|
|
|
|
|
2022.7629188, 24.172203, 128.3057, |
|
531
|
|
|
|
|
|
|
-1973.6517951, 0.636717, 348.1074, |
|
532
|
|
|
|
|
|
|
1240.2321818, 31.983787, 292.7252, |
|
533
|
|
|
|
|
|
|
953.8679112, 3.138886, 165.1686, |
|
534
|
|
|
|
|
|
|
-931.7537108, 30.973257, 263.7951, |
|
535
|
|
|
|
|
|
|
872.3795383, 44.828336, 15.3747, |
|
536
|
|
|
|
|
|
|
606.3544732, 0.991874, 58.5749, |
|
537
|
|
|
|
|
|
|
-496.0274038, 0.373813, 40.8226, |
|
538
|
|
|
|
|
|
|
456.9608039, 43.668246, 308.4258, |
|
539
|
|
|
|
|
|
|
346.9462320, 32.246691, 240.0099, |
|
540
|
|
|
|
|
|
|
-305.8412902, 30.599444, 222.9725, |
|
541
|
|
|
|
|
|
|
249.6173246, 2.147012, 106.5937, |
|
542
|
|
|
|
|
|
|
-199.1027200, 10.511172, 114.5182, |
|
543
|
|
|
|
|
|
|
191.0560889, 42.681324, 268.7809, |
|
544
|
|
|
|
|
|
|
-175.2936572, 13.650058, 279.6869, |
|
545
|
|
|
|
|
|
|
165.9068833, 0.986922, 39.6448, |
|
546
|
|
|
|
|
|
|
161.1285917, 9.874455, 126.4108, |
|
547
|
|
|
|
|
|
|
139.7878093, 13.013341, 291.5795, |
|
548
|
|
|
|
|
|
|
-133.5228399, 0.262904, 307.2848, |
|
549
|
|
|
|
|
|
|
117.0673811, 0.004952, 18.9300, |
|
550
|
|
|
|
|
|
|
104.6907281, 1.142024, 273.7596, |
|
551
|
|
|
|
|
|
|
95.3227476, 63.219948, 143.8050, |
|
552
|
|
|
|
|
|
|
86.7824524, 0.205021, 191.8927, |
|
553
|
|
|
|
|
|
|
86.0857729, 2.151964, 125.5237, |
|
554
|
|
|
|
|
|
|
70.5893698, 64.230478, 172.7351, |
|
555
|
|
|
|
|
|
|
-69.9719343, 43.836462, 316.7998, |
|
556
|
|
|
|
|
|
|
-62.5817473, 47.439436, 319.6024, |
|
557
|
|
|
|
|
|
|
61.5450059, 1.384343, 69.7526, |
|
558
|
|
|
|
|
|
|
-57.9364011, 7.437771, 123.5968, |
|
559
|
|
|
|
|
|
|
57.1899832, 18.829299, 217.6432, |
|
560
|
|
|
|
|
|
|
-57.0236109, 9.500642, 85.5882, |
|
561
|
|
|
|
|
|
|
-54.2119253, 0.431696, 156.2147, |
|
562
|
|
|
|
|
|
|
53.2834147, 1.160090, 66.9489, |
|
563
|
|
|
|
|
|
|
52.1223575, 55.782177, 20.2082, |
|
564
|
|
|
|
|
|
|
-49.0059908, 12.639528, 250.7568, |
|
565
|
|
|
|
|
|
|
-48.3118757, 1.155138, 48.0188, |
|
566
|
|
|
|
|
|
|
-45.4191685, 0.168216, 8.3739, |
|
567
|
|
|
|
|
|
|
-42.2357920, 1.647247, 17.0374, |
|
568
|
|
|
|
|
|
|
-34.7971099, 10.884985, 155.3409, |
|
569
|
|
|
|
|
|
|
34.4623613, 5.610937, 94.1709, |
|
570
|
|
|
|
|
|
|
-33.8356643, 12.658184, 221.1120, |
|
571
|
|
|
|
|
|
|
33.6689362, 1.010530, 28.9300, |
|
572
|
|
|
|
|
|
|
-31.2521586, 1.983748, 117.1498, |
|
573
|
|
|
|
|
|
|
-30.8798701, 14.023871, 320.5095, |
|
574
|
|
|
|
|
|
|
28.4640769, 0.560178, 262.3602, |
|
575
|
|
|
|
|
|
|
-27.1960802, 1.273434, 336.2148, |
|
576
|
|
|
|
|
|
|
27.0860736, 12.021467, 233.0046, |
|
577
|
|
|
|
|
|
|
-26.3437456, 62.583231, 155.6977, |
|
578
|
|
|
|
|
|
|
24.7253740, 63.593761, 184.6277, |
|
579
|
|
|
|
|
|
|
24.6732126, 76.438310, 267.2772, |
|
580
|
|
|
|
|
|
|
24.4272733, 4.280910, 78.9281, |
|
581
|
|
|
|
|
|
|
24.0127327, 13.218362, 123.4722, |
|
582
|
|
|
|
|
|
|
21.7150294, 17.818769, 188.7132, |
|
583
|
|
|
|
|
|
|
-21.5375347, 8.359495, 180.1364, |
|
584
|
|
|
|
|
|
|
18.1148363, 56.792707, 49.1382, |
|
585
|
|
|
|
|
|
|
-16.9603104, 8.448301, 152.5268, |
|
586
|
|
|
|
|
|
|
-16.1765215, 1.978796, 98.2198, |
|
587
|
|
|
|
|
|
|
15.5567653, 8.863925, 97.4808, |
|
588
|
|
|
|
|
|
|
15.4846529, 0.186365, 221.5376, |
|
589
|
|
|
|
|
|
|
15.2150632, 8.996212, 168.2438, |
|
590
|
|
|
|
|
|
|
14.5047426, 6.771027, 161.1199, |
|
591
|
|
|
|
|
|
|
-14.3873316, 45.815258, 55.0196, |
|
592
|
|
|
|
|
|
|
13.1351419, 12.002811, 262.6495, |
|
593
|
|
|
|
|
|
|
12.8776311, 75.278220, 200.3284, |
|
594
|
|
|
|
|
|
|
11.9867234, 65.241008, 201.6651, |
|
595
|
|
|
|
|
|
|
11.9385578, 18.870667, 294.6547, |
|
596
|
|
|
|
|
|
|
11.7030822, 22.009553, 99.8233, |
|
597
|
|
|
|
|
|
|
11.6018181, 64.604291, 213.5577, |
|
598
|
|
|
|
|
|
|
-11.2617293, 11.498094, 154.1631, |
|
599
|
|
|
|
|
|
|
-10.4664199, 0.578834, 232.7153, |
|
600
|
|
|
|
|
|
|
10.4333970, 9.237738, 138.3034, |
|
601
|
|
|
|
|
|
|
-10.2377466, 49.747842, 204.6609, |
|
602
|
|
|
|
|
|
|
10.1934446, 2.147012, 106.5938, |
|
603
|
|
|
|
|
|
|
-10.1280191, 1.196895, 250.4676, |
|
604
|
|
|
|
|
|
|
10.0289441, 2.133898, 332.3345, |
|
605
|
|
|
|
|
|
|
-10.0034259, 0.173168, 27.3039 |
|
606
|
|
|
|
|
|
|
); |
|
607
|
|
|
|
|
|
|
|
|
608
|
0
|
|
|
|
|
|
my $YM1950 = $self->{year} - 1950; |
|
609
|
|
|
|
|
|
|
#print "YM1950 : $YM1950\n"; |
|
610
|
|
|
|
|
|
|
|
|
611
|
0
|
|
|
|
|
|
my $PIz180 = $self->{CONSTANTS}->{TWOPI} / 360; |
|
612
|
|
|
|
|
|
|
#print "PIz180 : $PIz180\n"; |
|
613
|
|
|
|
|
|
|
|
|
614
|
|
|
|
|
|
|
#--------------------# |
|
615
|
|
|
|
|
|
|
# Obliquity from Table 1 (2): |
|
616
|
|
|
|
|
|
|
#--------------------# |
|
617
|
|
|
|
|
|
|
# OBLIQ = 23.320556 (degrees) Equation 5.5 (15) |
|
618
|
|
|
|
|
|
|
# OBLIQD = OBLIQ + sum[A cos(ft+delta)] Equation 1 (5) |
|
619
|
0
|
|
|
|
|
|
my $sumc = 0; |
|
620
|
0
|
|
|
|
|
|
for (my $i = 0; $i < 47; $i++) { |
|
621
|
|
|
|
|
|
|
#printf "%2d => 1=%18.8f 2=%18.8f 3=%18.8f\n", $i, $table1[(($i*3)+0)], $table1[(($i*3)+1)], $table1[(($i*3)+2)]; |
|
622
|
0
|
|
|
|
|
|
my $arg = $PIz180 * ($YM1950 * $table1[(($i*3)+1)] / 3600 + $table1[(($i*3)+2)]); |
|
623
|
0
|
|
|
|
|
|
$sumc = $sumc + $table1[(($i*3)+0)] * cos($arg); |
|
624
|
|
|
|
|
|
|
#print "$arg - $sumc\n"; |
|
625
|
|
|
|
|
|
|
} |
|
626
|
0
|
|
|
|
|
|
my $OBLIQD = 23.320556 + $sumc/3600; |
|
627
|
|
|
|
|
|
|
#print "OBLIQD : $OBLIQD\n"; |
|
628
|
0
|
|
|
|
|
|
$self->{SCRATCH}->{OBLIQ} = $OBLIQD * $PIz180; |
|
629
|
|
|
|
|
|
|
#print "OBLIQ : " . $self->{SCRATCH}->{OBLIQ} . "\n"; |
|
630
|
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
#--------------------# |
|
632
|
|
|
|
|
|
|
# Eccentricity from Table 4 (1): |
|
633
|
|
|
|
|
|
|
#--------------------# |
|
634
|
|
|
|
|
|
|
# ECCEN sin(pi) = sum[M sin(gt+beta)] Equation 4 (1) |
|
635
|
|
|
|
|
|
|
# ECCEN cos(pi) = sum[M cos(gt+beta)] Equation 4 (1) |
|
636
|
|
|
|
|
|
|
# ECCEN = ECCEN sqrt[sin(pi)^2 + cos(pi)^2] |
|
637
|
0
|
|
|
|
|
|
my $ESINPI = 0; |
|
638
|
0
|
|
|
|
|
|
my $ECOSPI = 0; |
|
639
|
0
|
|
|
|
|
|
for (my $i = 0; $i < 19; $i++) { |
|
640
|
|
|
|
|
|
|
#printf "%2d => 1=%18.8f 2=%18.8f 3=%18.8f\n", $i, $table4[(($i*3)+0)], $table4[(($i*3)+1)], $table4[(($i*3)+2)]; |
|
641
|
0
|
|
|
|
|
|
my $arg = $PIz180 * ($YM1950 * $table4[(($i*3)+1)] / 3600 + $table4[(($i*3)+2)]); |
|
642
|
0
|
|
|
|
|
|
$ESINPI = $ESINPI + $table4[(($i*3)+0)] * sin($arg); |
|
643
|
0
|
|
|
|
|
|
$ECOSPI = $ECOSPI + $table4[(($i*3)+0)] * cos($arg); |
|
644
|
|
|
|
|
|
|
#print "ESINPI : $ESINPI\n"; |
|
645
|
|
|
|
|
|
|
#print "ECOSPI : $ECOSPI\n"; |
|
646
|
|
|
|
|
|
|
} |
|
647
|
0
|
|
|
|
|
|
$self->{SCRATCH}->{ECCEN} = sqrt(($ESINPI * $ESINPI) + ($ECOSPI * $ECOSPI)); |
|
648
|
|
|
|
|
|
|
#print "ECCEN : " . $self->{SCRATCH}->{ECCEN} . "\n"; |
|
649
|
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
#--------------------# |
|
651
|
|
|
|
|
|
|
# Perihelion from Equation 4,6,7 (9) and Table 4,5 (1,3): |
|
652
|
|
|
|
|
|
|
#--------------------# |
|
653
|
|
|
|
|
|
|
# PSI# = 50.439273 (seconds of degree) Equation 7.5 (16) |
|
654
|
|
|
|
|
|
|
# ZETA = 3.392506 (degrees) Equation 7.5 (17) |
|
655
|
|
|
|
|
|
|
# PSI = PSI# t + ZETA + sum[F sin(ft+delta)] Equation 7 (9) |
|
656
|
|
|
|
|
|
|
# PIE = atan[ECCEN sin(pi) / ECCEN cos(pi)] |
|
657
|
|
|
|
|
|
|
# OMEGVP = PIE + PSI + 3.14159 Equation 6 (4.5) |
|
658
|
|
|
|
|
|
|
|
|
659
|
0
|
|
|
|
|
|
my $PIE = atan2($ESINPI, $ECOSPI); |
|
660
|
|
|
|
|
|
|
#print "PIE : $PIE\n"; |
|
661
|
0
|
|
|
|
|
|
my $FSINFD = 0; |
|
662
|
0
|
|
|
|
|
|
for(my $i = 0; $i < 78; $i++) { |
|
663
|
|
|
|
|
|
|
#printf "%2d => 1=%18.8f 2=%18.8f 3=%18.8f\n", $i, $table5[(($i*3)+0)], $table5[(($i*3)+1)], $table5[(($i*3)+2)]; |
|
664
|
0
|
|
|
|
|
|
my $arg = $PIz180 * ($YM1950 * $table5[(($i*3)+1)] / 3600 + $table5[(($i*3)+2)]); |
|
665
|
0
|
|
|
|
|
|
$FSINFD = $FSINFD + $table5[(($i*3)+0)] * sin($arg); |
|
666
|
|
|
|
|
|
|
} |
|
667
|
|
|
|
|
|
|
#print "FSINFD : $FSINFD\n"; |
|
668
|
0
|
|
|
|
|
|
my $PSI = $PIz180 * (3.392506 + ($YM1950 * 50.439273 + $FSINFD) / 3600); |
|
669
|
|
|
|
|
|
|
#print "PSI : $PSI\n"; |
|
670
|
0
|
|
|
|
|
|
my $a = ($PIE + $PSI + .5 * $self->{CONSTANTS}->{TWOPI}) ; |
|
671
|
0
|
|
|
|
|
|
my $b = $self->{CONSTANTS}->{TWOPI}; |
|
672
|
0
|
|
|
|
|
|
my $c = $a / $b; |
|
673
|
0
|
|
|
|
|
|
my $d = modulo($a, $b); |
|
674
|
|
|
|
|
|
|
#printf "%25.20f\n", $a; |
|
675
|
|
|
|
|
|
|
#printf "%25.20f\n", $b; |
|
676
|
|
|
|
|
|
|
#printf "%25.20f\n", $c; |
|
677
|
|
|
|
|
|
|
#printf "%25.20f\n", $d; |
|
678
|
0
|
|
|
|
|
|
$self->{SCRATCH}->{OMEGVP} = modulo(($PIE + $PSI + .5 * $self->{CONSTANTS}->{TWOPI}), $self->{CONSTANTS}->{TWOPI}); |
|
679
|
|
|
|
|
|
|
#print "OMEGVP : " . $self->{SCRATCH}->{OMEGVP} . "\n"; |
|
680
|
|
|
|
|
|
|
} |
|
681
|
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
#----------------------------------------# |
|
683
|
|
|
|
|
|
|
# ORBIT receives orbital parameters and time of year, and returns |
|
684
|
|
|
|
|
|
|
# distance from Sun and Sun's position. |
|
685
|
|
|
|
|
|
|
# Reference for following caculations is: V.M.Blanco and |
|
686
|
|
|
|
|
|
|
# S.W.McCuskey, 1961, "Basic Physics of the Solar System", pages |
|
687
|
|
|
|
|
|
|
# 135 - 151. Existence of Moon and heavenly bodies other than |
|
688
|
|
|
|
|
|
|
# Earth and Sun are ignored. Earth is assumed to be spherical. |
|
689
|
|
|
|
|
|
|
# |
|
690
|
|
|
|
|
|
|
# Program author: Gary L. Russell 2002/09/25 |
|
691
|
|
|
|
|
|
|
# Angles, longitude and latitude are measured in radians. |
|
692
|
|
|
|
|
|
|
# |
|
693
|
|
|
|
|
|
|
# Input: ECCEN = ECCENtricity of the orbital ellipse |
|
694
|
|
|
|
|
|
|
# OBLIQ = latitude of Tropic of Cancer |
|
695
|
|
|
|
|
|
|
# OMEGVP = longitude of perihelion (sometimes Pi is added) = |
|
696
|
|
|
|
|
|
|
# = spatial angle from vernal equinox to perihelion |
|
697
|
|
|
|
|
|
|
# with Sun as angle vertex |
|
698
|
|
|
|
|
|
|
# DAY = days measured since 2000 January 1, hour 0 |
|
699
|
|
|
|
|
|
|
# |
|
700
|
|
|
|
|
|
|
# Constants: EDAYzY = tropical year = Earth days per year = 365.2425 |
|
701
|
|
|
|
|
|
|
# VE200D = days from 2000 January 1, hour 0 till vernal |
|
702
|
|
|
|
|
|
|
# equinox of year 2000 = 31 + 29 + 19 + 7.5/24 |
|
703
|
|
|
|
|
|
|
# |
|
704
|
|
|
|
|
|
|
# Intermediate quantities: |
|
705
|
|
|
|
|
|
|
# BSEMI = semi minor axis in units of semi major axis |
|
706
|
|
|
|
|
|
|
# PERIHE = perihelion in days since 2000 January 1, hour 0 |
|
707
|
|
|
|
|
|
|
# in its annual revolution about Sun |
|
708
|
|
|
|
|
|
|
# TA = true anomaly = spatial angle from perihelion to |
|
709
|
|
|
|
|
|
|
# current location with Sun as angle vertex |
|
710
|
|
|
|
|
|
|
# EA = ECCENtric anomaly = spatial angle measured along |
|
711
|
|
|
|
|
|
|
# ECCENtric circle (that circumscribes Earth's orbit) |
|
712
|
|
|
|
|
|
|
# from perihelion to point above (or below) Earth's |
|
713
|
|
|
|
|
|
|
# absisca (where absisca is directed from center of |
|
714
|
|
|
|
|
|
|
# ECCENtric circle to perihelion) |
|
715
|
|
|
|
|
|
|
# MA = mean anomaly = temporal angle from perihelion to |
|
716
|
|
|
|
|
|
|
# current time in units of 2*Pi per tropical year |
|
717
|
|
|
|
|
|
|
# TAofVE = TA(VE) = true anomaly of vernal equinox = - OMEGVP |
|
718
|
|
|
|
|
|
|
# EAofVE = EA(VE) = ECCENtric anomaly of vernal equinox |
|
719
|
|
|
|
|
|
|
# MAofVE = MA(VE) = mean anomaly of vernal equinox |
|
720
|
|
|
|
|
|
|
# SLNORO = longitude of Sun in Earth's nonrotating reference frame |
|
721
|
|
|
|
|
|
|
# VEQLON = longitude of Greenwich Meridion in Earth's nonrotating |
|
722
|
|
|
|
|
|
|
# reference frame at vernal equinox |
|
723
|
|
|
|
|
|
|
# ROTATE = change in longitude in Earth's nonrotating reference |
|
724
|
|
|
|
|
|
|
# frame from point's location on vernal equinox to its |
|
725
|
|
|
|
|
|
|
# current location where point is fixed on rotating Earth |
|
726
|
|
|
|
|
|
|
# SLMEAN = longitude of fictitious mean Sun in Earth's rotating |
|
727
|
|
|
|
|
|
|
# reference frame (normal longitude and latitude) |
|
728
|
|
|
|
|
|
|
# |
|
729
|
|
|
|
|
|
|
# Output: DIST = distance to Sun in units of semi major axis |
|
730
|
|
|
|
|
|
|
# SIND = sine of declination angle = sin(SUNLAT) |
|
731
|
|
|
|
|
|
|
# COSD = cosine of the declination angle = cos(SUNLAT) |
|
732
|
|
|
|
|
|
|
# SUNLON = longitude of point on Earth directly beneath Sun |
|
733
|
|
|
|
|
|
|
# SUNLAT = latitude of point on Earth directly beneath Sun |
|
734
|
|
|
|
|
|
|
# EQTIME = Equation of Time = longitude of fictitious mean Sun minus SUNLON |
|
735
|
|
|
|
|
|
|
# |
|
736
|
|
|
|
|
|
|
# From the above reference: |
|
737
|
|
|
|
|
|
|
# (4-54): [1 - ECCEN*cos(EA)]*[1 + ECCEN*cos(TA)] = (1 - ECCEN^2) |
|
738
|
|
|
|
|
|
|
# (4-55): tan(TA/2) = sqrt[(1+ECCEN)/(1-ECCEN)]*tan(EA/2) |
|
739
|
|
|
|
|
|
|
# Yield: tan(EA) = sin(TA)*sqrt(1-ECCEN^2) / [cos(TA) + ECCEN] |
|
740
|
|
|
|
|
|
|
# or: tan(TA) = sin(EA)*sqrt(1-ECCEN^2) / [cos(EA) - ECCEN] |
|
741
|
|
|
|
|
|
|
# |
|
742
|
|
|
|
|
|
|
# Use C540, Only: EDAYzY,VE200D,CONSTANTS}->{TWOPI |
|
743
|
|
|
|
|
|
|
# Implicit Real*8 (A-H,M-Z) |
|
744
|
|
|
|
|
|
|
#----------------------------------------# |
|
745
|
|
|
|
|
|
|
sub ORBIT { |
|
746
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
747
|
0
|
|
|
|
|
|
my $DAY = shift; |
|
748
|
|
|
|
|
|
|
|
|
749
|
0
|
|
|
|
|
|
my $EDAYzY = 365.2425; |
|
750
|
0
|
|
|
|
|
|
my $VE200D = 79.3125; |
|
751
|
|
|
|
|
|
|
|
|
752
|
|
|
|
|
|
|
# Determine EAofVE from geometry: tan(EA) = b*sin(TA) / [e+cos(TA)] |
|
753
|
|
|
|
|
|
|
# Determine MAofVE from Kepler's equation: MA = EA - e*sin(EA) |
|
754
|
|
|
|
|
|
|
# Determine MA knowing time from vernal equinox to current day |
|
755
|
|
|
|
|
|
|
|
|
756
|
|
|
|
|
|
|
#printf "DAY : %.10f\n", $DAY; |
|
757
|
|
|
|
|
|
|
#printf "ECCEN : %.10f\n", $self->{SCRATCH}->{ECCEN}; |
|
758
|
|
|
|
|
|
|
#printf "OMEGVP : %.10f\n", $self->{SCRATCH}->{OMEGVP}; |
|
759
|
|
|
|
|
|
|
|
|
760
|
0
|
|
|
|
|
|
my $BSEMI = sqrt(1 - ($self->{SCRATCH}->{ECCEN} * $self->{SCRATCH}->{ECCEN})); |
|
761
|
|
|
|
|
|
|
#printf "BSEMI : %.10f\n", $BSEMI; |
|
762
|
|
|
|
|
|
|
|
|
763
|
0
|
|
|
|
|
|
my $TAofVE = -($self->{SCRATCH}->{OMEGVP}); |
|
764
|
|
|
|
|
|
|
#printf "TAofVE : %.10f\n", $TAofVE; |
|
765
|
|
|
|
|
|
|
|
|
766
|
0
|
|
|
|
|
|
my $EAofVE = atan2( ($BSEMI * sin($TAofVE)), ($self->{SCRATCH}->{ECCEN} + cos($TAofVE)) ); |
|
767
|
|
|
|
|
|
|
#printf "EAofVE : %.10f\n", $EAofVE; |
|
768
|
|
|
|
|
|
|
|
|
769
|
0
|
|
|
|
|
|
my $MAofVE = $EAofVE - $self->{SCRATCH}->{ECCEN} * sin($EAofVE); |
|
770
|
|
|
|
|
|
|
#printf "MAofVE : %.10f\n", $MAofVE; |
|
771
|
|
|
|
|
|
|
|
|
772
|
0
|
|
|
|
|
|
my $MA = modulo(($self->{CONSTANTS}->{TWOPI} * ($DAY - $VE200D) / $EDAYzY + $MAofVE), $self->{CONSTANTS}->{TWOPI}); |
|
773
|
|
|
|
|
|
|
#printf "MA : $MA\n"; |
|
774
|
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
# Numerically invert Kepler's equation: MA = EA - e*sin(EA) |
|
776
|
0
|
|
|
|
|
|
my $dEA = 1; |
|
777
|
0
|
|
|
|
|
|
my $i = 0; |
|
778
|
0
|
|
|
|
|
|
my $EA = $MA + ($self->{SCRATCH}->{ECCEN} * ( sin($MA)) + ($self->{SCRATCH}->{ECCEN} * sin( 2 * $MA ) / 2) ); |
|
779
|
0
|
|
|
|
|
|
while (abs($dEA) > 0.0000000001){ |
|
780
|
0
|
|
|
|
|
|
$dEA = ($MA - $EA + $self->{SCRATCH}->{ECCEN} * sin($EA)) / (1 - $self->{SCRATCH}->{ECCEN} * cos($EA)); |
|
781
|
0
|
|
|
|
|
|
$EA += $dEA; |
|
782
|
|
|
|
|
|
|
#printf "computing $i times ($EA, $dEA - %25.20f)\n", (abs($dEA)); |
|
783
|
0
|
|
|
|
|
|
$i++; |
|
784
|
|
|
|
|
|
|
} |
|
785
|
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
# |
|
787
|
|
|
|
|
|
|
# Calculate distance to Sun and true anomaly |
|
788
|
|
|
|
|
|
|
# |
|
789
|
0
|
|
|
|
|
|
my $SUNDIS = 1 - $self->{SCRATCH}->{ECCEN} * cos($EA); |
|
790
|
0
|
|
|
|
|
|
my $TA = atan2( ($BSEMI * sin($EA)), (cos($EA) - $self->{SCRATCH}->{ECCEN})); |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
# |
|
793
|
|
|
|
|
|
|
# Change reference frame to be nonrotating reference frame, angles |
|
794
|
|
|
|
|
|
|
# fixed according to stars, with Earth at center and positive x |
|
795
|
|
|
|
|
|
|
# axis be ray from Earth to Sun were Earth at vernal equinox, and |
|
796
|
|
|
|
|
|
|
# x-y plane be Earth's equatorial plane. Distance from current Sun |
|
797
|
|
|
|
|
|
|
# to this x axis is SUNDIS sin(TA-TAofVE). At vernal equinox, Sun |
|
798
|
|
|
|
|
|
|
# is located at (SUNDIS,0,0). At other times, Sun is located at: |
|
799
|
|
|
|
|
|
|
# |
|
800
|
|
|
|
|
|
|
# SUN = (SUNDIS cos(TA-TAofVE), |
|
801
|
|
|
|
|
|
|
# SUNDIS sin(TA-TAofVE) cos(OBLIQ), |
|
802
|
|
|
|
|
|
|
# SUNDIS sin(TA-TAofVE) sin(OBLIQ)) |
|
803
|
|
|
|
|
|
|
# |
|
804
|
0
|
|
|
|
|
|
my $SIND = sin($TA - $TAofVE) * sin($self->{SCRATCH}->{OBLIQ}); |
|
805
|
0
|
|
|
|
|
|
my $COSD = sqrt(1 - ($SIND * $SIND)); |
|
806
|
0
|
|
|
|
|
|
my $SUNX = cos($TA - $TAofVE); |
|
807
|
0
|
|
|
|
|
|
my $SUNY = sin($TA - $TAofVE) * cos($self->{SCRATCH}->{OBLIQ}); |
|
808
|
0
|
|
|
|
|
|
my $SLNORO = atan2($SUNY, $SUNX); |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
# |
|
811
|
|
|
|
|
|
|
# Determine Sun location in Earth's rotating reference frame |
|
812
|
|
|
|
|
|
|
# (normal longitude and latitude) |
|
813
|
|
|
|
|
|
|
# |
|
814
|
0
|
|
|
|
|
|
my $VEQLON = $self->{CONSTANTS}->{TWOPI} * $VE200D - $self->{CONSTANTS}->{TWOPI} / 2 + $MAofVE - $TAofVE; # modulo 2*Pi |
|
815
|
0
|
|
|
|
|
|
my $ROTATE = $self->{CONSTANTS}->{TWOPI} * ($DAY - $VE200D) * ($EDAYzY + 1) / $EDAYzY; |
|
816
|
0
|
|
|
|
|
|
my $SUNLON = modulo(($SLNORO - $ROTATE - $VEQLON), $self->{CONSTANTS}->{TWOPI}); |
|
817
|
0
|
0
|
|
|
|
|
if ($SUNLON > ($self->{CONSTANTS}->{TWOPI} / 2)) { |
|
818
|
0
|
|
|
|
|
|
$SUNLON = $SUNLON - $self->{CONSTANTS}->{TWOPI}; |
|
819
|
|
|
|
|
|
|
} |
|
820
|
0
|
|
|
|
|
|
my $SUNLAT = asin(sin($TA - $TAofVE) * sin($self->{SCRATCH}->{OBLIQ})); |
|
821
|
|
|
|
|
|
|
|
|
822
|
|
|
|
|
|
|
# |
|
823
|
|
|
|
|
|
|
# Determine longitude of fictitious mean Sun |
|
824
|
|
|
|
|
|
|
# Calculate Equation of Time |
|
825
|
|
|
|
|
|
|
# |
|
826
|
0
|
|
|
|
|
|
my $SLMEAN = $self->{CONSTANTS}->{TWOPI} / 2 - $self->{CONSTANTS}->{TWOPI} * ($DAY - int($DAY)); |
|
827
|
0
|
|
|
|
|
|
my $EQTIME = modulo($SLMEAN - $SUNLON, $self->{CONSTANTS}->{TWOPI}); |
|
828
|
0
|
0
|
|
|
|
|
if ($EQTIME > $self->{CONSTANTS}->{TWOPI}/2) { |
|
829
|
0
|
|
|
|
|
|
$EQTIME = $EQTIME - $self->{CONSTANTS}->{TWOPI}; |
|
830
|
|
|
|
|
|
|
} |
|
831
|
|
|
|
|
|
|
|
|
832
|
0
|
|
|
|
|
|
return ($SIND, $COSD, $SUNDIS, $SUNLON, $SUNLAT, $EQTIME); |
|
833
|
|
|
|
|
|
|
} |
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
#----------------------------------------# |
|
836
|
|
|
|
|
|
|
# SUNSET |
|
837
|
|
|
|
|
|
|
# Input: RLAT = latitude (degrees) |
|
838
|
|
|
|
|
|
|
# SIND,COSD = sine and cosine of the declination angle |
|
839
|
|
|
|
|
|
|
# RSmEzM = (Sun Radius - Earth Radius) / (distance to Sun) |
|
840
|
|
|
|
|
|
|
# |
|
841
|
|
|
|
|
|
|
# Output: DUSK = time of DUSK (temporal radians) at mean local time |
|
842
|
|
|
|
|
|
|
# |
|
843
|
|
|
|
|
|
|
#----------------------------------------# |
|
844
|
|
|
|
|
|
|
sub SUNSET { |
|
845
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
846
|
0
|
|
|
|
|
|
my $RLAT = $self->{latitude};; |
|
847
|
0
|
|
|
|
|
|
my $SIND = shift; |
|
848
|
0
|
|
|
|
|
|
my $COSD = shift; |
|
849
|
0
|
|
|
|
|
|
my $RSmEzM = shift; |
|
850
|
|
|
|
|
|
|
|
|
851
|
0
|
|
|
|
|
|
my $DUSK = 0; |
|
852
|
|
|
|
|
|
|
|
|
853
|
0
|
|
|
|
|
|
my $SINJ = sin( $self->{CONSTANTS}->{TWOPI} * $self->{latitude} / 360); |
|
854
|
0
|
|
|
|
|
|
my $COSJ = cos( $self->{CONSTANTS}->{TWOPI} * $self->{latitude} / 360); |
|
855
|
0
|
|
|
|
|
|
my $SJSD = $SINJ * $SIND; |
|
856
|
0
|
|
|
|
|
|
my $CJCD = $COSJ * $COSD; |
|
857
|
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
# Constant nightime at this latitude |
|
859
|
0
|
0
|
|
|
|
|
if (($SJSD + $RSmEzM + $CJCD) <= 0) { |
|
860
|
0
|
|
|
|
|
|
$DUSK = -999999; |
|
861
|
0
|
|
|
|
|
|
return $DUSK; |
|
862
|
|
|
|
|
|
|
} |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
# Constant daylight at this latitude |
|
865
|
0
|
0
|
|
|
|
|
if (($SJSD + $RSmEzM - $CJCD) >= 0) { |
|
866
|
0
|
|
|
|
|
|
$DUSK = 999999; |
|
867
|
0
|
|
|
|
|
|
return $DUSK; |
|
868
|
|
|
|
|
|
|
} |
|
869
|
|
|
|
|
|
|
|
|
870
|
|
|
|
|
|
|
# Compute DUSK (at local time) |
|
871
|
0
|
|
|
|
|
|
my $CDUSK = -($SJSD + $RSmEzM) / $CJCD; # cosine of DUSK |
|
872
|
0
|
|
|
|
|
|
$DUSK = acos($CDUSK); |
|
873
|
|
|
|
|
|
|
|
|
874
|
0
|
|
|
|
|
|
return $DUSK; |
|
875
|
|
|
|
|
|
|
} |
|
876
|
|
|
|
|
|
|
|
|
877
|
|
|
|
|
|
|
#----------------------------------------# |
|
878
|
|
|
|
|
|
|
# For a given JYEAR (A.D.), JMONTH and DATE (between 0 and 31), |
|
879
|
|
|
|
|
|
|
# calculate number of DAYs measured from 2000 January 1, hour 0. |
|
880
|
|
|
|
|
|
|
#----------------------------------------# |
|
881
|
|
|
|
|
|
|
sub YMDtoD { |
|
882
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
883
|
0
|
|
|
|
|
|
my $JYEAR = shift; |
|
884
|
0
|
|
|
|
|
|
my $JMONTH = shift; |
|
885
|
0
|
|
|
|
|
|
my $DATE = shift; |
|
886
|
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
#print "year : $JYEAR\n"; |
|
888
|
|
|
|
|
|
|
#print "month : $JMONTH\n"; |
|
889
|
|
|
|
|
|
|
#print "date : $DATE\n"; |
|
890
|
|
|
|
|
|
|
|
|
891
|
0
|
|
|
|
|
|
my $JDAY4C = 365 * 400 + 97; # number of days in 4 centuries |
|
892
|
0
|
|
|
|
|
|
my $JDAY1C = 365 * 100 + 24; # number of days in 1 century |
|
893
|
0
|
|
|
|
|
|
my $JDAY4Y = 365 * 4 + 1; # number of days in 4 years |
|
894
|
0
|
|
|
|
|
|
my $JDAY1Y = 365; # number of days in 1 year |
|
895
|
|
|
|
|
|
|
|
|
896
|
0
|
|
|
|
|
|
my @JDSUMN = (0,31,59, 90,120,151, 181,212,243, 273,304,334); |
|
897
|
0
|
|
|
|
|
|
my @JDSUML = (0,31,60, 91,121,152, 182,213,244, 274,305,335); |
|
898
|
|
|
|
|
|
|
|
|
899
|
0
|
|
|
|
|
|
my $N4CENT = int( ($JYEAR-2000) / 400); |
|
900
|
0
|
|
|
|
|
|
my $IYR4C = $JYEAR - 2000 - ($N4CENT * 400); |
|
901
|
0
|
|
|
|
|
|
my $N1CENT = int($IYR4C / 100); |
|
902
|
0
|
|
|
|
|
|
my $IYR1C = $IYR4C - $N1CENT * 100; |
|
903
|
0
|
|
|
|
|
|
my $N4YEAR = int($IYR1C / 4); |
|
904
|
0
|
|
|
|
|
|
my $IYR4Y = $IYR1C - $N4YEAR * 4; |
|
905
|
0
|
|
|
|
|
|
my $N1YEAR = $IYR4Y; |
|
906
|
0
|
|
|
|
|
|
my $DAY = $N4CENT * $JDAY4C; |
|
907
|
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
#print "N4CENT : $N4CENT\n"; |
|
909
|
|
|
|
|
|
|
#print "IYR4C : $IYR4C\n"; |
|
910
|
|
|
|
|
|
|
#print "N1CENT : $N1CENT\n"; |
|
911
|
|
|
|
|
|
|
#print "IYR1C : $IYR1C\n"; |
|
912
|
|
|
|
|
|
|
#print "N4YEAR : $N4YEAR\n"; |
|
913
|
|
|
|
|
|
|
#print "IYR4Y : $IYR4Y\n"; |
|
914
|
|
|
|
|
|
|
#print "N1YEAR : $N1YEAR\n"; |
|
915
|
|
|
|
|
|
|
#print "DAY : $DAY\n"; |
|
916
|
|
|
|
|
|
|
|
|
917
|
0
|
0
|
|
|
|
|
if ($N1CENT > 0) { |
|
918
|
0
|
|
|
|
|
|
$DAY = $DAY + $JDAY1C + 1 + ($N1CENT - 1) * $JDAY1C; |
|
919
|
|
|
|
|
|
|
#print "1. $DAY\n"; |
|
920
|
0
|
0
|
|
|
|
|
if ($N4YEAR > 0) { |
|
921
|
|
|
|
|
|
|
#print "2. $DAY\n"; |
|
922
|
0
|
|
|
|
|
|
$DAY = $DAY + $JDAY4Y-1 + ($N4YEAR - 1) * $JDAY4Y; |
|
923
|
0
|
0
|
|
|
|
|
if ($N1YEAR > 0) { |
|
924
|
|
|
|
|
|
|
#print "3. $DAY\n"; |
|
925
|
0
|
|
|
|
|
|
$DAY = $DAY + $JDAY1Y+1 + ($N1YEAR - 1) * $JDAY1Y; |
|
926
|
|
|
|
|
|
|
#print "4. $DAY\n"; |
|
927
|
0
|
|
|
|
|
|
$DAY = $DAY + $JDSUMN[($JMONTH - 1)] + $DATE; |
|
928
|
|
|
|
|
|
|
#print "5. $DAY\n"; |
|
929
|
0
|
|
|
|
|
|
return $DAY; |
|
930
|
|
|
|
|
|
|
} else { |
|
931
|
0
|
|
|
|
|
|
$DAY = $DAY + $JDSUML[($JMONTH - 1)] + $DATE; |
|
932
|
|
|
|
|
|
|
#print "6. $DAY\n"; |
|
933
|
0
|
|
|
|
|
|
return $DAY; |
|
934
|
|
|
|
|
|
|
} |
|
935
|
|
|
|
|
|
|
} else { |
|
936
|
|
|
|
|
|
|
#print "day : -> $DAY\n"; |
|
937
|
|
|
|
|
|
|
#print "month : -> $JMONTH\n"; |
|
938
|
|
|
|
|
|
|
#print "date : -> $DATE\n"; |
|
939
|
|
|
|
|
|
|
#print "index : -> " . $JDSUML[$JMONTH] . "\n"; |
|
940
|
0
|
|
|
|
|
|
$DAY = $DAY + $JDSUML[($JMONTH - 1)] + $DATE; |
|
941
|
|
|
|
|
|
|
#print "7. - $DAY\n"; |
|
942
|
0
|
|
|
|
|
|
return $DAY; |
|
943
|
|
|
|
|
|
|
} |
|
944
|
|
|
|
|
|
|
} else { |
|
945
|
|
|
|
|
|
|
|
|
946
|
0
|
|
|
|
|
|
$DAY = $DAY + ($N4YEAR * $JDAY4Y); |
|
947
|
|
|
|
|
|
|
#print "8. $DAY\n"; |
|
948
|
|
|
|
|
|
|
|
|
949
|
0
|
0
|
|
|
|
|
if ($N1YEAR > 0) { |
|
950
|
0
|
|
|
|
|
|
$DAY = $DAY + ($JDAY1Y + 1) + (($N1YEAR - 1) * $JDAY1Y); |
|
951
|
|
|
|
|
|
|
#print "9. $DAY\n"; |
|
952
|
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
#print "JMONTH " . $JMONTH . "\n"; |
|
954
|
|
|
|
|
|
|
#print "JDSUMN " . $JDSUMN[($JMONTH - 1)] . "\n"; |
|
955
|
|
|
|
|
|
|
|
|
956
|
0
|
|
|
|
|
|
$DAY = $DAY + $JDSUMN[($JMONTH - 1)] + $DATE; |
|
957
|
|
|
|
|
|
|
#print "10. $DAY\n"; |
|
958
|
|
|
|
|
|
|
|
|
959
|
0
|
|
|
|
|
|
return $DAY; |
|
960
|
|
|
|
|
|
|
} else { |
|
961
|
0
|
|
|
|
|
|
$DAY = $DAY + $JDSUML[($JMONTH - 1)] + $DATE; |
|
962
|
|
|
|
|
|
|
#print "11. $DAY\n"; |
|
963
|
0
|
|
|
|
|
|
return $DAY; |
|
964
|
|
|
|
|
|
|
} |
|
965
|
|
|
|
|
|
|
} |
|
966
|
|
|
|
|
|
|
} |
|
967
|
|
|
|
|
|
|
|
|
968
|
|
|
|
|
|
|
#----------------------------------------# |
|
969
|
|
|
|
|
|
|
# For a given DAY measured from 2000 January 1, hour 0, determine |
|
970
|
|
|
|
|
|
|
# the JYEAR (A.D.), JMONTH and DATE (between 0 and 31). |
|
971
|
|
|
|
|
|
|
#----------------------------------------# |
|
972
|
|
|
|
|
|
|
sub DtoYMD { |
|
973
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
974
|
0
|
|
|
|
|
|
my $DAY = shift; |
|
975
|
|
|
|
|
|
|
|
|
976
|
0
|
|
|
|
|
|
my $JDAY4C = 365*400 + 97; # number of days in 4 centuries |
|
977
|
0
|
|
|
|
|
|
my $JDAY1C = 365*100 + 24; # number of days in 1 century |
|
978
|
0
|
|
|
|
|
|
my $JDAY4Y = 365* 4 + 1, # number of days in 4 years |
|
979
|
|
|
|
|
|
|
my $JDAY1Y = 365; # number of days in 1 year |
|
980
|
|
|
|
|
|
|
|
|
981
|
0
|
|
|
|
|
|
my @JDSUMN = (0,31,59, 90,120,151, 181,212,243, 273,304,334); |
|
982
|
0
|
|
|
|
|
|
my @JDSUML = (0,31,60, 91,121,152, 182,213,244, 274,305,335); |
|
983
|
|
|
|
|
|
|
|
|
984
|
|
|
|
|
|
|
#my $N4CENT = int($DAY / $JDAY4C); |
|
985
|
|
|
|
|
|
|
#my $DAY4C = $DAY - $N4CENT * $JDAY4C; |
|
986
|
|
|
|
|
|
|
#my $N1CENT = ($DAY4C - 1) / $JDAY1C; |
|
987
|
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
# Second to fourth of every fourth century: 21??, 22??, 23??, etc. |
|
989
|
|
|
|
|
|
|
#if ($N1CENT > 0) { |
|
990
|
|
|
|
|
|
|
# $DAY1C = $DAY4C - $N1CENT * $JDAY1C - 1; |
|
991
|
|
|
|
|
|
|
# $N4YEAR = ($DAY1C + 1) / $JDAY4Y; |
|
992
|
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
# if ($N4YEAR > 0) { |
|
994
|
|
|
|
|
|
|
# # Subsequent four years of every second to fourth century when |
|
995
|
|
|
|
|
|
|
# # there is a leap year: 2104-2107, 2108-2111 ... 2204-2207, etc. |
|
996
|
|
|
|
|
|
|
# $DAY4Y = $DAY1C - $N4YEAR * $JDAY4Y + 1; |
|
997
|
|
|
|
|
|
|
# $N1YEAR = ($DAY4Y - 1) / $JDAY1Y; |
|
998
|
|
|
|
|
|
|
# if ($N1YEAR > 0) { |
|
999
|
|
|
|
|
|
|
# # Current year is not a leap frog year |
|
1000
|
|
|
|
|
|
|
# $DAY1Y = $DAY4Y - $N1YEAR * $JDAY1Y - 1; |
|
1001
|
|
|
|
|
|
|
# } |
|
1002
|
|
|
|
|
|
|
#} |
|
1003
|
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
# First of every fourth century: 16??, 20??, 24??, etc. |
|
1005
|
|
|
|
|
|
|
#$DAY1C = $DAY4C; |
|
1006
|
|
|
|
|
|
|
#$N4YEAR = $DAY1C / JDAY4Y; |
|
1007
|
|
|
|
|
|
|
#$DAY4Y = $DAY1C - $N4YEAR * $JDAY4Y; |
|
1008
|
|
|
|
|
|
|
#$N1YEAR = ($DAY4Y - 1) / $JDAY1Y; |
|
1009
|
|
|
|
|
|
|
#if (N1YEAR > 0) { |
|
1010
|
|
|
|
|
|
|
# # Current year is not a leap frog year |
|
1011
|
|
|
|
|
|
|
# $DAY1Y = $DAY4Y - $N1YEAR * $JDAY1Y - 1; |
|
1012
|
|
|
|
|
|
|
#} |
|
1013
|
|
|
|
|
|
|
|
|
1014
|
|
|
|
|
|
|
# GoTo 100 |
|
1015
|
|
|
|
|
|
|
|
|
1016
|
|
|
|
|
|
|
# First four years of every second to fourth century when there is |
|
1017
|
|
|
|
|
|
|
# no leap year: 2100-2103, 2200-2203, 2300-2303, etc. |
|
1018
|
|
|
|
|
|
|
# DAY4Y = DAY1C |
|
1019
|
|
|
|
|
|
|
# N1YEAR = DAY4Y/JDAY1Y |
|
1020
|
|
|
|
|
|
|
# DAY1Y = DAY4Y - N1YEAR*JDAY1Y |
|
1021
|
|
|
|
|
|
|
# GoTo 210 |
|
1022
|
|
|
|
|
|
|
|
|
1023
|
|
|
|
|
|
|
# |
|
1024
|
|
|
|
|
|
|
# Current year is a leap frog year |
|
1025
|
|
|
|
|
|
|
# |
|
1026
|
|
|
|
|
|
|
#100 DAY1Y = DAY4Y |
|
1027
|
|
|
|
|
|
|
# Do 120 M=1,11 |
|
1028
|
|
|
|
|
|
|
#120 If (DAY1Y < JDSUML(M+1)) GoTo 130 |
|
1029
|
|
|
|
|
|
|
#C M=12 |
|
1030
|
|
|
|
|
|
|
#130 JYEAR = 2000 + N4CENT*400 + N1CENT*100 + N4YEAR*4 + N1YEAR |
|
1031
|
|
|
|
|
|
|
# JMONTH = M |
|
1032
|
|
|
|
|
|
|
# DATE = DAY1Y - JDSUML(M) |
|
1033
|
|
|
|
|
|
|
# Return |
|
1034
|
|
|
|
|
|
|
|
|
1035
|
|
|
|
|
|
|
# |
|
1036
|
|
|
|
|
|
|
# Current year is not a leap frog year |
|
1037
|
|
|
|
|
|
|
# |
|
1038
|
|
|
|
|
|
|
#210 Do 220 M=1,11 |
|
1039
|
|
|
|
|
|
|
#220 If (DAY1Y < JDSUMN(M+1)) GoTo 230 |
|
1040
|
|
|
|
|
|
|
#C M=12 |
|
1041
|
|
|
|
|
|
|
#230 JYEAR = 2000 + N4CENT*400 + N1CENT*100 + N4YEAR*4 + N1YEAR |
|
1042
|
|
|
|
|
|
|
# JMONTH = M |
|
1043
|
|
|
|
|
|
|
# DATE = DAY1Y - JDSUMN(M) |
|
1044
|
|
|
|
|
|
|
# Return |
|
1045
|
|
|
|
|
|
|
# End |
|
1046
|
|
|
|
|
|
|
} |
|
1047
|
|
|
|
|
|
|
|
|
1048
|
|
|
|
|
|
|
#----------------------------------------# |
|
1049
|
|
|
|
|
|
|
# For a given year, VERNAL calculates an approximate time of vernal |
|
1050
|
|
|
|
|
|
|
# equinox in days measured from 2000 January 1, hour 0. |
|
1051
|
|
|
|
|
|
|
|
|
1052
|
|
|
|
|
|
|
# VERNAL assumes that vernal equinoxes from one year to the next |
|
1053
|
|
|
|
|
|
|
# are separated by exactly 365.2425 days, a tropical year |
|
1054
|
|
|
|
|
|
|
# [Explanatory Supplement to The Astronomical Ephemeris]. If the |
|
1055
|
|
|
|
|
|
|
# tropical year is 365.2422 days, as indicated by other references, |
|
1056
|
|
|
|
|
|
|
# then the time of the vernal equinox will be off by 2.88 hours in |
|
1057
|
|
|
|
|
|
|
# 400 years. |
|
1058
|
|
|
|
|
|
|
|
|
1059
|
|
|
|
|
|
|
# Time of vernal equinox for year 2000 A.D. is March 20, 7:36 GMT |
|
1060
|
|
|
|
|
|
|
# [NASA Reference Publication 1349, Oct. 1994]. VERNAL assumes |
|
1061
|
|
|
|
|
|
|
# that vernal equinox for year 2000 will be on March 20, 7:30, or |
|
1062
|
|
|
|
|
|
|
# 79.3125 days from 2000 January 1, hour 0. Vernal equinoxes for |
|
1063
|
|
|
|
|
|
|
# other years returned by VERNAL are also measured in days from |
|
1064
|
|
|
|
|
|
|
# 2000 January 1, hour 0. 79.3125 = 31 + 29 + 19 + 7.5/24. |
|
1065
|
|
|
|
|
|
|
sub vernal { |
|
1066
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
1067
|
0
|
|
|
|
|
|
my $JYEAR = shift; |
|
1068
|
|
|
|
|
|
|
|
|
1069
|
0
|
|
|
|
|
|
my $EDAYzY = 365.2425; |
|
1070
|
0
|
|
|
|
|
|
my $VE200D = 79.3125; |
|
1071
|
0
|
|
|
|
|
|
my $VERNAL = $VE200D + ($JYEAR - 2000) * $EDAYzY; |
|
1072
|
|
|
|
|
|
|
} |
|
1073
|
|
|
|
|
|
|
|
|
1074
|
|
|
|
|
|
|
#----------------------------------------# |
|
1075
|
|
|
|
|
|
|
# QLEAPY |
|
1076
|
|
|
|
|
|
|
# Determine whether the given JYEAR is a Leap Year or not. |
|
1077
|
|
|
|
|
|
|
#----------------------------------------# |
|
1078
|
|
|
|
|
|
|
sub QLEAPY { |
|
1079
|
0
|
|
|
0
|
0
|
|
my $year = shift; |
|
1080
|
|
|
|
|
|
|
|
|
1081
|
0
|
0
|
|
|
|
|
if(!($year%4)) { |
|
1082
|
0
|
0
|
|
|
|
|
if($year%100) { |
|
1083
|
0
|
|
|
|
|
|
return(0); # if leap year |
|
1084
|
|
|
|
|
|
|
} else { |
|
1085
|
0
|
0
|
|
|
|
|
if(!($year%400)) { |
|
1086
|
0
|
|
|
|
|
|
return(0); |
|
1087
|
|
|
|
|
|
|
} |
|
1088
|
0
|
|
|
|
|
|
return(1) |
|
1089
|
|
|
|
|
|
|
} |
|
1090
|
|
|
|
|
|
|
} |
|
1091
|
|
|
|
|
|
|
|
|
1092
|
0
|
|
|
|
|
|
return 1; # if it is not leap year |
|
1093
|
|
|
|
|
|
|
} |
|
1094
|
|
|
|
|
|
|
|
|
1095
|
|
|
|
|
|
|
#----------------------------------------# |
|
1096
|
|
|
|
|
|
|
# COSZIJ calculates the daily average cosine of the zenith angle |
|
1097
|
|
|
|
|
|
|
# weighted by time and weighted by sunlight. |
|
1098
|
|
|
|
|
|
|
# |
|
1099
|
|
|
|
|
|
|
# Input: RLAT = latitude (degrees) |
|
1100
|
|
|
|
|
|
|
# SIND,COSD = sine and cosine of the declination angle |
|
1101
|
|
|
|
|
|
|
# |
|
1102
|
|
|
|
|
|
|
# Output: COSZT = sum(cosZ*dT) / sum(dT) |
|
1103
|
|
|
|
|
|
|
# COSZS = sum(cosZ*cosZ*dT) / sum(cosZ*dT) |
|
1104
|
|
|
|
|
|
|
# |
|
1105
|
|
|
|
|
|
|
# Intern: DAWN = time of DAWN (temporal radians) at mean local time |
|
1106
|
|
|
|
|
|
|
# DUSK = time of DUSK (temporal radians) at mean local time |
|
1107
|
|
|
|
|
|
|
#----------------------------------------# |
|
1108
|
|
|
|
|
|
|
sub COSZIJ { |
|
1109
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
1110
|
0
|
|
|
|
|
|
my $SIND = shift; |
|
1111
|
0
|
|
|
|
|
|
my $COSD = shift; |
|
1112
|
|
|
|
|
|
|
|
|
1113
|
0
|
|
|
|
|
|
my $DUSK = 0; |
|
1114
|
0
|
|
|
|
|
|
my $CDUSK = 0; |
|
1115
|
0
|
|
|
|
|
|
my $SDUSK = 0; |
|
1116
|
0
|
|
|
|
|
|
my $DAWN = 0; |
|
1117
|
0
|
|
|
|
|
|
my $S2DUSK = 0; |
|
1118
|
0
|
|
|
|
|
|
my $SDAWN = 0; |
|
1119
|
0
|
|
|
|
|
|
my $S2DAWN = 0; |
|
1120
|
0
|
|
|
|
|
|
my $COSZT = 0; |
|
1121
|
0
|
|
|
|
|
|
my $COSZS = 0; |
|
1122
|
0
|
|
|
|
|
|
my $ECOSZ = 0; |
|
1123
|
0
|
|
|
|
|
|
my $QCOSZ = 0; |
|
1124
|
|
|
|
|
|
|
|
|
1125
|
0
|
|
|
|
|
|
my $SINJ = sin($self->{CONSTANTS}->{TWOPI} * $self->{latitude} / 360); |
|
1126
|
|
|
|
|
|
|
#print "sinj : $SINJ\n"; |
|
1127
|
0
|
|
|
|
|
|
my $COSJ = cos($self->{CONSTANTS}->{TWOPI} * $self->{latitude} / 360); |
|
1128
|
|
|
|
|
|
|
#print "cosj : $COSJ\n"; |
|
1129
|
|
|
|
|
|
|
|
|
1130
|
0
|
|
|
|
|
|
my $SJSD = $SINJ * $SIND; |
|
1131
|
0
|
|
|
|
|
|
my $CJCD = $COSJ * $COSD; |
|
1132
|
|
|
|
|
|
|
|
|
1133
|
|
|
|
|
|
|
# Constant nightime at this latitude |
|
1134
|
0
|
0
|
|
|
|
|
if ( ($SJSD + $CJCD) <= 0) { |
|
1135
|
0
|
|
|
|
|
|
$DAWN = 999999; |
|
1136
|
0
|
|
|
|
|
|
$DUSK = 999999; |
|
1137
|
0
|
|
|
|
|
|
$COSZT = 0; |
|
1138
|
0
|
|
|
|
|
|
$COSZS = 0; |
|
1139
|
|
|
|
|
|
|
} |
|
1140
|
|
|
|
|
|
|
|
|
1141
|
|
|
|
|
|
|
# Constant daylight at this latitude |
|
1142
|
0
|
0
|
|
|
|
|
if ( ($SJSD - $CJCD) >= 0) { |
|
1143
|
0
|
|
|
|
|
|
$DAWN = -999999; |
|
1144
|
0
|
|
|
|
|
|
$DUSK = -999999; |
|
1145
|
0
|
|
|
|
|
|
$ECOSZ = $SJSD * $self->{CONSTANTS}->{TWOPI}; |
|
1146
|
0
|
|
|
|
|
|
$QCOSZ = $SJSD * $ECOSZ + .5 * $CJCD * $CJCD * $self->{CONSTANTS}->{TWOPI}; |
|
1147
|
0
|
|
|
|
|
|
$COSZT = $SJSD; # = ECOSZ/$self->{CONSTANTS}->{TWOPI} |
|
1148
|
0
|
|
|
|
|
|
$COSZS = $QCOSZ / $ECOSZ; |
|
1149
|
|
|
|
|
|
|
} |
|
1150
|
|
|
|
|
|
|
|
|
1151
|
|
|
|
|
|
|
# Compute DAWN and DUSK (at local time) and their sines |
|
1152
|
0
|
|
|
|
|
|
$CDUSK = - ($SJSD / $CJCD); |
|
1153
|
0
|
|
|
|
|
|
$DUSK = acos($CDUSK); |
|
1154
|
0
|
|
|
|
|
|
$SDUSK = sqrt( $CJCD * $CJCD - $SJSD * $SJSD) / $CJCD; |
|
1155
|
0
|
|
|
|
|
|
$S2DUSK = 2 * $SDUSK * $CDUSK; |
|
1156
|
0
|
|
|
|
|
|
$DAWN = -$DUSK; |
|
1157
|
0
|
|
|
|
|
|
$SDAWN = -$SDUSK; |
|
1158
|
0
|
|
|
|
|
|
$S2DAWN = -$S2DUSK; |
|
1159
|
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
# Nightime at initial and final times with daylight in between |
|
1161
|
0
|
|
|
|
|
|
$ECOSZ = $SJSD * ($DUSK-$DAWN) + $CJCD * ($SDUSK - $SDAWN); |
|
1162
|
0
|
|
|
|
|
|
$QCOSZ = $SJSD * $ECOSZ + $CJCD * ($SJSD * ($SDUSK - $SDAWN) +.5 * $CJCD * ($DUSK - $DAWN + .5 * ($S2DUSK-$S2DAWN) ) ); |
|
1163
|
0
|
|
|
|
|
|
$COSZT = $ECOSZ / $self->{CONSTANTS}->{TWOPI}; |
|
1164
|
0
|
|
|
|
|
|
$COSZS = $QCOSZ / $ECOSZ; |
|
1165
|
|
|
|
|
|
|
|
|
1166
|
0
|
|
|
|
|
|
return ($COSZT, $COSZS); |
|
1167
|
|
|
|
|
|
|
} |
|
1168
|
|
|
|
|
|
|
|
|
1169
|
|
|
|
|
|
|
# my own div because we're getting nowhere with '%' |
|
1170
|
|
|
|
|
|
|
# this is such a hack |
|
1171
|
|
|
|
|
|
|
# a = 49.2 |
|
1172
|
|
|
|
|
|
|
# b = 6.23 |
|
1173
|
|
|
|
|
|
|
# a/b = 7.89 |
|
1174
|
|
|
|
|
|
|
# d = 7 |
|
1175
|
|
|
|
|
|
|
# e = 89 |
|
1176
|
|
|
|
|
|
|
# return 49.2 - (7 * 6.23) |
|
1177
|
|
|
|
|
|
|
sub modulo { |
|
1178
|
0
|
|
|
0
|
0
|
|
my $a = shift; |
|
1179
|
0
|
|
|
|
|
|
my $b = shift; |
|
1180
|
0
|
|
|
|
|
|
my ($d, $e) = split(/\./, ($a/$b), 2); |
|
1181
|
|
|
|
|
|
|
|
|
1182
|
0
|
|
|
|
|
|
return ($a - ($d * $b)); |
|
1183
|
|
|
|
|
|
|
} |
|
1184
|
|
|
|
|
|
|
|
|
1185
|
|
|
|
|
|
|
# my own round up because the one that I found on perlmonks.org |
|
1186
|
|
|
|
|
|
|
# didn't work well |
|
1187
|
|
|
|
|
|
|
sub _roundup { |
|
1188
|
0
|
|
|
0
|
|
|
my $a = shift; |
|
1189
|
0
|
|
|
|
|
|
my ($b, $c) = split(/\./, $a, 2); |
|
1190
|
|
|
|
|
|
|
|
|
1191
|
0
|
0
|
|
|
|
|
if (($a-$b) >= .5) { |
|
1192
|
0
|
|
|
|
|
|
return ($b+1); |
|
1193
|
|
|
|
|
|
|
} |
|
1194
|
|
|
|
|
|
|
|
|
1195
|
0
|
|
|
|
|
|
return $b; |
|
1196
|
|
|
|
|
|
|
} |
|
1197
|
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
1; |
|
1199
|
|
|
|
|
|
|
|
|
1200
|
|
|
|
|
|
|
__END__ |