DrRandom

sunTimes_NewCalc.cpp

Aug 23rd, 2022
821
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.16 KB | Source Code | 0 0
  1. #include <utilities/sunTimes.h>
  2.  
  3. /* +++Date last modified: 05-Jul-1997 */
  4. /* Updated comments, 05-Aug-2013 */
  5.  
  6. /*
  7.  
  8. SUNRISET.C - computes Sun rise/set times, start/end of twilight, and
  9.              the length of the day at any date and latitude
  10.  
  11. Written as DAYLEN.C, 1989-08-16
  12.  
  13. Modified to SUNRISET.C, 1992-12-01
  14.  
  15. (c) Paul Schlyter, 1989, 1992
  16.  
  17. Released to the public domain by Paul Schlyter, December 1992
  18.  
  19. */
  20.  
  21. /* The "workhorse" function for sun rise/set times */
  22.  
  23. int sunTimes::__sunriset__( int year, int month, int day, double lon, double lat,
  24.                   double altit, int upper_limb, double *trise, double *tset )
  25. /***************************************************************************/
  26. /* Note: year,month,date = calendar date, 1801-2099 only.             */
  27. /*       Eastern longitude positive, Western longitude negative       */
  28. /*       Northern latitude positive, Southern latitude negative       */
  29. /*       The longitude value IS critical in this function!            */
  30. /*       altit = the altitude which the Sun should cross              */
  31. /*               Set to -35/60 degrees for rise/set, -6 degrees       */
  32. /*               for civil, -12 degrees for nautical and -18          */
  33. /*               degrees for astronomical twilight.                   */
  34. /*         upper_limb: non-zero -> upper limb, zero -> center         */
  35. /*               Set to non-zero (e.g. 1) when computing rise/set     */
  36. /*               times, and to zero when computing start/end of       */
  37. /*               twilight.                                            */
  38. /*        *rise = where to store the rise time                        */
  39. /*        *set  = where to store the set  time                        */
  40. /*                Both times are relative to the specified altitude,  */
  41. /*                and thus this function can be used to compute       */
  42. /*                various twilight times, as well as rise/set times   */
  43. /* Return value:  0 = sun rises/sets this day, times stored at        */
  44. /*                    *trise and *tset.                               */
  45. /*               +1 = sun above the specified "horizon" 24 hours.     */
  46. /*                    *trise set to time when the sun is at south,    */
  47. /*                    minus 12 hours while *tset is set to the south  */
  48. /*                    time plus 12 hours. "Day" length = 24 hours     */
  49. /*               -1 = sun is below the specified "horizon" 24 hours   */
  50. /*                    "Day" length = 0 hours, *trise and *tset are    */
  51. /*                    both set to the time when the sun is at south.  */
  52. /*                                                                    */
  53. /**********************************************************************/
  54. {
  55.       double  d,  /* Days since 2000 Jan 0.0 (negative before) */
  56.       sr,         /* Solar distance, astronomical units */
  57.       sRA,        /* Sun's Right Ascension */
  58.       sdec,       /* Sun's declination */
  59.       sradius,    /* Sun's apparent radius */
  60.       t,          /* Diurnal arc */
  61.       tsouth,     /* Time when Sun is at south */
  62.       sidtime;    /* Local sidereal time */
  63.  
  64.       int rc = 0; /* Return cde from function - usually 0 */
  65.  
  66.       /* Compute d of 12h local mean solar time */
  67.       d = days_since_2000_Jan_0(year,month,day) + 0.5 - lon/360.0;
  68.  
  69.       /* Compute the local sidereal time of this moment */
  70.       sidtime = revolution( GMST0(d) + 180.0 + lon );
  71.  
  72.       /* Compute Sun's RA, Decl and distance at this moment */
  73.       sun_RA_dec( d, &sRA, &sdec, &sr );
  74.  
  75.       /* Compute time when Sun is at south - in hours UT */
  76.       tsouth = 12.0 - rev180(sidtime - sRA)/15.0;
  77.  
  78.       /* Compute the Sun's apparent radius in degrees */
  79.       sradius = 0.2666 / sr;
  80.  
  81.       /* Do correction to upper limb, if necessary */
  82.       if ( upper_limb )
  83.             altit -= sradius;
  84.  
  85.       /* Compute the diurnal arc that the Sun traverses to reach */
  86.       /* the specified altitude altit: */
  87.       {
  88.             double cost;
  89.             cost = ( sind(altit) - sind(lat) * sind(sdec) ) /
  90.                   ( cosd(lat) * cosd(sdec) );
  91.             if ( cost >= 1.0 )
  92.                   rc = -1, t = 0.0;       /* Sun always below altit */
  93.             else if ( cost <= -1.0 )
  94.                   rc = +1, t = 12.0;      /* Sun always above altit */
  95.             else
  96.                   t = acosd(cost)/15.0;   /* The diurnal arc, hours */
  97.       }
  98.  
  99.       /* Store rise and set times - in hours UT */
  100.       *trise = tsouth - t;
  101.       *tset  = tsouth + t;
  102.  
  103.       return rc;
  104. }  /* __sunriset__ */
  105.  
  106.  
  107.  
  108. /* The "workhorse" function */
  109.  
  110.  
  111. double sunTimes::__daylen__( int year, int month, int day, double lon, double lat,
  112.                    double altit, int upper_limb )
  113. /**********************************************************************/
  114. /* Note: year,month,date = calendar date, 1801-2099 only.             */
  115. /*       Eastern longitude positive, Western longitude negative       */
  116. /*       Northern latitude positive, Southern latitude negative       */
  117. /*       The longitude value is not critical. Set it to the correct   */
  118. /*       longitude if you're picky, otherwise set to to, say, 0.0     */
  119. /*       The latitude however IS critical - be sure to get it correct */
  120. /*       altit = the altitude which the Sun should cross              */
  121. /*               Set to -35/60 degrees for rise/set, -6 degrees       */
  122. /*               for civil, -12 degrees for nautical and -18          */
  123. /*               degrees for astronomical twilight.                   */
  124. /*         upper_limb: non-zero -> upper limb, zero -> center         */
  125. /*               Set to non-zero (e.g. 1) when computing day length   */
  126. /*               and to zero when computing day+twilight length.      */
  127. /**********************************************************************/
  128. {
  129.       double  d,  /* Days since 2000 Jan 0.0 (negative before) */
  130.       obl_ecl,    /* Obliquity (inclination) of Earth's axis */
  131.       sr,         /* Solar distance, astronomical units */
  132.       slon,       /* True solar longitude */
  133.       sin_sdecl,  /* Sine of Sun's declination */
  134.       cos_sdecl,  /* Cosine of Sun's declination */
  135.       sradius,    /* Sun's apparent radius */
  136.       t;          /* Diurnal arc */
  137.  
  138.       /* Compute d of 12h local mean solar time */
  139.       d = days_since_2000_Jan_0(year,month,day) + 0.5 - lon/360.0;
  140.  
  141.       /* Compute obliquity of ecliptic (inclination of Earth's axis) */
  142.       obl_ecl = 23.4393 - 3.563E-7 * d;
  143.  
  144.       /* Compute Sun's ecliptic longitude and distance */
  145.       sunpos( d, &slon, &sr );
  146.  
  147.       /* Compute sine and cosine of Sun's declination */
  148.       sin_sdecl = sind(obl_ecl) * sind(slon);
  149.       cos_sdecl = sqrt( 1.0 - sin_sdecl * sin_sdecl );
  150.  
  151.       /* Compute the Sun's apparent radius, degrees */
  152.       sradius = 0.2666 / sr;
  153.  
  154.       /* Do correction to upper limb, if necessary */
  155.       if ( upper_limb )
  156.             altit -= sradius;
  157.  
  158.       /* Compute the diurnal arc that the Sun traverses to reach */
  159.       /* the specified altitude altit: */
  160.       {
  161.             double cost;
  162.             cost = ( sind(altit) - sind(lat) * sin_sdecl ) /
  163.                   ( cosd(lat) * cos_sdecl );
  164.             if ( cost >= 1.0 )
  165.                   t = 0.0;                      /* Sun always below altit */
  166.             else if ( cost <= -1.0 )
  167.                   t = 24.0;                     /* Sun always above altit */
  168.             else  t = (2.0/15.0) * acosd(cost); /* The diurnal arc, hours */
  169.       }
  170.       return t;
  171. }  /* __daylen__ */
  172.  
  173.  
  174. /* This function computes the Sun's position at any instant */
  175.  
  176. void sunTimes::sunpos( double d, double *lon, double *r )
  177. /******************************************************/
  178. /* Computes the Sun's ecliptic longitude and distance */
  179. /* at an instant given in d, number of days since     */
  180. /* 2000 Jan 0.0.  The Sun's ecliptic latitude is not  */
  181. /* computed, since it's always very near 0.           */
  182. /******************************************************/
  183. {
  184.       double M,         /* Mean anomaly of the Sun */
  185.              w,         /* Mean longitude of perihelion */
  186.                         /* Note: Sun's mean longitude = M + w */
  187.              e,         /* Eccentricity of Earth's orbit */
  188.              E,         /* Eccentric anomaly */
  189.              x, y,      /* x, y coordinates in orbit */
  190.              v;         /* True anomaly */
  191.  
  192.       /* Compute mean elements */
  193.       M = revolution( 356.0470 + 0.9856002585 * d );
  194.       w = 282.9404 + 4.70935E-5 * d;
  195.       e = 0.016709 - 1.151E-9 * d;
  196.  
  197.       /* Compute true longitude and radius vector */
  198.       E = M + e * RADEG * sind(M) * ( 1.0 + e * cosd(M) );
  199.             x = cosd(E) - e;
  200.       y = sqrt( 1.0 - e*e ) * sind(E);
  201.       *r = sqrt( x*x + y*y );              /* Solar distance */
  202.       v = atan2d( y, x );                  /* True anomaly */
  203.       *lon = v + w;                        /* True solar longitude */
  204.       if ( *lon >= 360.0 )
  205.             *lon -= 360.0;                   /* Make it 0..360 degrees */
  206. }
  207.  
  208. void sunTimes::sun_RA_dec( double d, double *RA, double *dec, double *r )
  209. /******************************************************/
  210. /* Computes the Sun's equatorial coordinates RA, Decl */
  211. /* and also its distance, at an instant given in d,   */
  212. /* the number of days since 2000 Jan 0.0.             */
  213. /******************************************************/
  214. {
  215.       double lon, obl_ecl, x, y, z;
  216.  
  217.       /* Compute Sun's ecliptical coordinates */
  218.       sunpos( d, &lon, r );
  219.  
  220.       /* Compute ecliptic rectangular coordinates (z=0) */
  221.       x = *r * cosd(lon);
  222.       y = *r * sind(lon);
  223.  
  224.       /* Compute obliquity of ecliptic (inclination of Earth's axis) */
  225.       obl_ecl = 23.4393 - 3.563E-7 * d;
  226.  
  227.       /* Convert to equatorial rectangular coordinates - x is unchanged */
  228.       z = y * sind(obl_ecl);
  229.       y = y * cosd(obl_ecl);
  230.  
  231.       /* Convert to spherical coordinates */
  232.       *RA = atan2d( y, x );
  233.       *dec = atan2d( z, sqrt(x*x + y*y) );
  234.  
  235. }  /* sun_RA_dec */
  236.  
  237.  
  238. /******************************************************************/
  239. /* This function reduces any angle to within the first revolution */
  240. /* by subtracting or adding even multiples of 360.0 until the     */
  241. /* result is >= 0.0 and < 360.0                                   */
  242. /******************************************************************/
  243.  
  244. #define INV360    ( 1.0 / 360.0 )
  245.  
  246. double sunTimes::revolution( double x )
  247. /*****************************************/
  248. /* Reduce angle to within 0..360 degrees */
  249. /*****************************************/
  250. {
  251.       return( x - 360.0 * floor( x * INV360 ) );
  252. }  /* revolution */
  253.  
  254. double sunTimes::rev180( double x )
  255. /*********************************************/
  256. /* Reduce angle to within +180..+180 degrees */
  257. /*********************************************/
  258. {
  259.       return( x - 360.0 * floor( x * INV360 + 0.5 ) );
  260. }  /* revolution */
  261.  
  262.  
  263. /*******************************************************************/
  264. /* This function computes GMST0, the Greenwich Mean Sidereal Time  */
  265. /* at 0h UT (i.e. the sidereal time at the Greenwhich meridian at  */
  266. /* 0h UT).  GMST is then the sidereal time at Greenwich at any     */
  267. /* time of the day.  I've generalized GMST0 as well, and define it */
  268. /* as:  GMST0 = GMST - UT  --  this allows GMST0 to be computed at */
  269. /* other times than 0h UT as well.  While this sounds somewhat     */
  270. /* contradictory, it is very practical:  instead of computing      */
  271. /* GMST like:                                                      */
  272. /*                                                                 */
  273. /*  GMST = (GMST0) + UT * (366.2422/365.2422)                      */
  274. /*                                                                 */
  275. /* where (GMST0) is the GMST last time UT was 0 hours, one simply  */
  276. /* computes:                                                       */
  277. /*                                                                 */
  278. /*  GMST = GMST0 + UT                                              */
  279. /*                                                                 */
  280. /* where GMST0 is the GMST "at 0h UT" but at the current moment!   */
  281. /* Defined in this way, GMST0 will increase with about 4 min a     */
  282. /* day.  It also happens that GMST0 (in degrees, 1 hr = 15 degr)   */
  283. /* is equal to the Sun's mean longitude plus/minus 180 degrees!    */
  284. /* (if we neglect aberration, which amounts to 20 seconds of arc   */
  285. /* or 1.33 seconds of time)                                        */
  286. /*                                                                 */
  287. /*******************************************************************/
  288.  
  289. double sunTimes::GMST0( double d )
  290. {
  291.       double sidtim0;
  292.       /* Sidtime at 0h UT = L (Sun's mean longitude) + 180.0 degr  */
  293.       /* L = M + w, as defined in sunpos().  Since I'm too lazy to */
  294.       /* add these numbers, I'll let the C compiler do it for me.  */
  295.       /* Any decent C compiler will add the constants at compile   */
  296.       /* time, imposing no runtime or code overhead.               */
  297.       sidtim0 = revolution( ( 180.0 + 356.0470 + 282.9404 ) +
  298.                           ( 0.9856002585 + 4.70935E-5 ) * d );
  299.       return sidtim0;
  300. }  /* GMST0 */
  301.  
  302.  
Advertisement
Add Comment
Please, Sign In to add comment