@@ -276,11 +276,13 @@ private static double getEquationOfTime(double julianCenturies) {
276
276
double geomMeanAnomalySun = getSunGeometricMeanAnomaly (julianCenturies );
277
277
double y = Math .tan (Math .toRadians (epsilon ) / 2.0 );
278
278
y *= y ;
279
- double sin2l0 = Math .sin (2.0 * Math .toRadians (geomMeanLongSun ));
280
- double sinm = Math .sin (Math .toRadians (geomMeanAnomalySun ));
281
- double cos2l0 = Math .cos (2.0 * Math .toRadians (geomMeanLongSun ));
282
- double sin4l0 = Math .sin (4.0 * Math .toRadians (geomMeanLongSun ));
283
- double sin2m = Math .sin (2.0 * Math .toRadians (geomMeanAnomalySun ));
279
+ double geomMeanLongSunRad = Math .toRadians (geomMeanLongSun );
280
+ double geomMeanAnomalySunRad = Math .toRadians (geomMeanAnomalySun );
281
+ double sin2l0 = Math .sin (2.0 * geomMeanLongSunRad );
282
+ double sinm = Math .sin (geomMeanAnomalySunRad );
283
+ double cos2l0 = Math .cos (2.0 * geomMeanLongSunRad );
284
+ double sin4l0 = Math .sin (4.0 * geomMeanLongSunRad );
285
+ double sin2m = Math .sin (2.0 * geomMeanAnomalySunRad );
284
286
double equationOfTime = y * sin2l0 - 2.0 * eccentricityEarthOrbit * sinm + 4.0 * eccentricityEarthOrbit * y
285
287
* sinm * cos2l0 - 0.5 * y * y * sin4l0 - 1.25 * eccentricityEarthOrbit * eccentricityEarthOrbit * sin2m ;
286
288
return Math .toDegrees (equationOfTime ) * 4.0 ;
@@ -303,7 +305,8 @@ private static double getEquationOfTime(double julianCenturies) {
303
305
private static double getSunHourAngle (double latitude , double solarDeclination , double zenith , SolarEvent solarEvent ) {
304
306
double latRad = Math .toRadians (latitude );
305
307
double sdRad = Math .toRadians (solarDeclination );
306
- double hourAngle = (Math .acos (Math .cos (Math .toRadians (zenith )) / (Math .cos (latRad ) * Math .cos (sdRad ))
308
+ double zRad = Math .toRadians (zenith );
309
+ double hourAngle = (Math .acos (Math .cos (zRad ) / (Math .cos (latRad ) * Math .cos (sdRad ))
307
310
- Math .tan (latRad ) * Math .tan (sdRad )));
308
311
309
312
if (solarEvent == SolarEvent .SUNSET ) {
@@ -453,21 +456,170 @@ private static double getSunRiseSetUTC(Calendar calendar, double latitude, doubl
453
456
454
457
// First calculates sunrise and approximate length of day
455
458
double equationOfTime = getEquationOfTime (tnoon );
456
- double solarDeclination = getSunDeclination (tnoon );
457
- double hourAngle = getSunHourAngle (latitude , solarDeclination , zenith , solarEvent );
459
+ double hourAngle = getSunHourAngle1 (julianDay , latitude , longitude , zenith , solarEvent );
460
+ if (Double .isNaN (hourAngle )) {
461
+ hourAngle = interpolateHourAngle1 (julianDay , latitude , longitude , zenith , solarEvent );
462
+ if (Double .isNaN (hourAngle )) {
463
+ return Double .NaN ;
464
+ }
465
+ }
458
466
double delta = longitude - Math .toDegrees (hourAngle );
459
467
double timeDiff = 4 * delta ;
460
468
double timeUTC = 720 + timeDiff - equationOfTime ;
461
469
462
470
// Second pass includes fractional Julian Day in gamma calc
463
471
double newt = getJulianCenturiesFromJulianDay (julianDay + timeUTC / 1440.0 );
464
472
equationOfTime = getEquationOfTime (newt );
465
-
466
- solarDeclination = getSunDeclination (newt );
467
- hourAngle = getSunHourAngle (latitude , solarDeclination , zenith , solarEvent );
473
+
474
+ hourAngle = getSunHourAngle2 (julianDay , latitude , longitude , zenith , solarEvent );
475
+ if (Double .isNaN (hourAngle )) {
476
+ hourAngle = interpolateHourAngle2 (julianDay , latitude , longitude , zenith , solarEvent );
477
+ if (Double .isNaN (hourAngle )) {
478
+ return Double .NaN ;
479
+ }
480
+ }
468
481
delta = longitude - Math .toDegrees (hourAngle );
469
482
timeDiff = 4 * delta ;
470
483
timeUTC = 720 + timeDiff - equationOfTime ;
471
484
return timeUTC ;
472
485
}
486
+
487
+ private static double getSunHourAngle1 (double julianDay , double latitude , double longitude , double zenith , SolarEvent solarEvent ) {
488
+ // Find the time of solar noon at the location, and use that declination.
489
+ // This is better than start of the Julian day
490
+ double noonmin = getSolarNoonUTC (julianDay , longitude );
491
+ double tnoon = getJulianCenturiesFromJulianDay (julianDay + noonmin / 1440.0 );
492
+
493
+ // First calculates sunrise and approximate length of day
494
+ double solarDeclination = getSunDeclination (tnoon );
495
+
496
+ return getSunHourAngle (latitude , solarDeclination , zenith , solarEvent );
497
+ }
498
+
499
+ private static double getSunHourAngle2 (double julianDay , double latitude , double longitude , double zenith , SolarEvent solarEvent ) {
500
+ // Find the time of solar noon at the location, and use that declination.
501
+ // This is better than start of the Julian day
502
+ double noonmin = getSolarNoonUTC (julianDay , longitude );
503
+ double tnoon = getJulianCenturiesFromJulianDay (julianDay + noonmin / 1440.0 );
504
+
505
+ // First calculates sunrise and approximate length of day
506
+ double equationOfTime = getEquationOfTime (tnoon );
507
+ double solarDeclination = getSunDeclination (tnoon );
508
+ double hourAngle = getSunHourAngle (latitude , solarDeclination , zenith , solarEvent );
509
+ double delta = longitude - Math .toDegrees (hourAngle );
510
+ double timeDiff = 4 * delta ;
511
+ double timeUTC = 720 + timeDiff - equationOfTime ;
512
+
513
+ // Second pass includes fractional Julian Day in gamma calc
514
+ double newt = getJulianCenturiesFromJulianDay (julianDay + timeUTC / 1440.0 );
515
+
516
+ solarDeclination = getSunDeclination (newt );
517
+ return getSunHourAngle (latitude , solarDeclination , zenith , solarEvent );
518
+ }
519
+
520
+ /**
521
+ * Use linear interpolation to calculate a missing angle.
522
+ */
523
+ private static double interpolateHourAngle1 (double julianDay , double latitude , double longitude , double zenith , SolarEvent solarEvent ) {
524
+ double hourAngle ;
525
+ double x1 = 0 ;
526
+ double y1 = 0 ;
527
+ double x2 = 0 ;
528
+ double y2 = 0 ;
529
+
530
+ double d = julianDay - 1 ;
531
+ final double dayFirst = Math .max (julianDay - 366 , 1 );
532
+ while (d >= dayFirst ) {
533
+ hourAngle = getSunHourAngle1 (d , latitude , longitude , zenith , solarEvent );
534
+
535
+ if (!Double .isNaN (hourAngle )) {
536
+ x1 = d ;
537
+ y1 = hourAngle ;
538
+ break ;
539
+ }
540
+ d --;
541
+ }
542
+
543
+ d = julianDay + 1 ;
544
+ final double dayLast = julianDay + 366 ;
545
+ while (d <= dayLast ) {
546
+ hourAngle = getSunHourAngle1 (d , latitude , longitude , zenith , solarEvent );
547
+
548
+ if (!Double .isNaN (hourAngle )) {
549
+ if (x1 == 0 ) {
550
+ x1 = d ;
551
+ y1 = hourAngle ;
552
+ d ++;
553
+ continue ;
554
+ }
555
+ x2 = d ;
556
+ y2 = hourAngle ;
557
+ break ;
558
+ }
559
+ d ++;
560
+ }
561
+
562
+ if ((x1 == 0 ) || (x2 == 0 )) {
563
+ return Double .NaN ;
564
+ }
565
+ double dx = x2 - x1 ;
566
+ if (dx == 0 ) {
567
+ return Double .NaN ;
568
+ }
569
+ double dy = y2 - y1 ;
570
+ return y1 + ((julianDay - x1 ) * dy / dx );
571
+ }
572
+
573
+ /**
574
+ * Use linear interpolation to calculate a missing angle.
575
+ */
576
+ private static double interpolateHourAngle2 (double julianDay , double latitude , double longitude , double zenith , SolarEvent solarEvent ) {
577
+ double hourAngle ;
578
+ double x1 = 0 ;
579
+ double y1 = 0 ;
580
+ double x2 = 0 ;
581
+ double y2 = 0 ;
582
+
583
+ double d = julianDay - 1 ;
584
+ final double dayFirst = Math .max (julianDay - 366 , 1 );
585
+ while (d >= dayFirst ) {
586
+ hourAngle = getSunHourAngle2 (d , latitude , longitude , zenith , solarEvent );
587
+
588
+ if (!Double .isNaN (hourAngle )) {
589
+ x1 = d ;
590
+ y1 = hourAngle ;
591
+ break ;
592
+ }
593
+ d --;
594
+ }
595
+
596
+ d = julianDay + 1 ;
597
+ final double dayLast = julianDay + 366 ;
598
+ while (d <= dayLast ) {
599
+ hourAngle = getSunHourAngle2 (d , latitude , longitude , zenith , solarEvent );
600
+
601
+ if (!Double .isNaN (hourAngle )) {
602
+ if (x1 == 0 ) {
603
+ x1 = d ;
604
+ y1 = hourAngle ;
605
+ d ++;
606
+ continue ;
607
+ }
608
+ x2 = d ;
609
+ y2 = hourAngle ;
610
+ break ;
611
+ }
612
+ d ++;
613
+ }
614
+
615
+ if ((x1 == 0 ) || (x2 == 0 )) {
616
+ return Double .NaN ;
617
+ }
618
+ double dx = x2 - x1 ;
619
+ if (dx == 0 ) {
620
+ return Double .NaN ;
621
+ }
622
+ double dy = y2 - y1 ;
623
+ return y1 + ((julianDay - x1 ) * dy / dx );
624
+ }
473
625
}
0 commit comments