2021-01-13 20:51:38 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								///////////////////////////////////////////////////////////////////////////////////
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Copyright (C) 2021 Jon Beniston, M7RCE                                        //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Copyright (C) 2004 Rutherford Appleton Laboratory                             //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Copyright (C) 2012 Science and Technology Facilities Council.                 //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//                                                                               //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// This program is free software; you can redistribute it and/or modify          //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// it under the terms of the GNU General Public License as published by          //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// the Free Software Foundation as version 3 of the License, or                  //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// (at your option) any later version.                                           //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//                                                                               //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// This program is distributed in the hope that it will be useful,               //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// but WITHOUT ANY WARRANTY; without even the implied warranty of                //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the                  //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// GNU General Public License V3 for more details.                               //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//                                                                               //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// You should have received a copy of the GNU General Public License             //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// along with this program. If not, see <http://www.gnu.org/licenses/>.          //
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								///////////////////////////////////////////////////////////////////////////////////
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <cmath> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <QRegExp> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <QDateTime> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  <QDebug> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "util/units.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "astronomy.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Function prototypes
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  palRefz ( double  zu ,  double  refa ,  double  refb ,  double  * zr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  palRefco  ( double  hm ,  double  tdk ,  double  pmb ,  double  rh , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                double  wl ,  double  phi ,  double  tlr ,  double  eps , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                double  * refa ,  double  * refb ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  palRefro (  double  zobs ,  double  hm ,  double  tdk ,  double  pmb , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								               double  rh ,  double  wl ,  double  phi ,  double  tlr , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								               double  eps ,  double  *  ref ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Calculate Julian date (days since January 1, 4713 BC) from Gregorian calendar date
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : julianDate ( int  year ,  int  month ,  int  day ,  int  hours ,  int  minutes ,  int  seconds ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    int  julian_day ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  julian_date ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // From: https://en.wikipedia.org/wiki/Julian_day
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    julian_day  =  ( 1461  *  ( year  +  4800  +  ( month  -  14 ) / 12 ) ) / 4  + ( 367  *  ( month  -  2  -  12  *  ( ( month  -  14 ) / 12 ) ) ) / 12  -  ( 3  *  ( ( year  +  4900  +  ( month  -  14 ) / 12 ) / 100 ) ) / 4  +  day  -  32075 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    julian_date  =  julian_day  +  ( hours / 24.0  -  0.5 )  +  minutes / ( 24.0 * 60.0 )  +  seconds / ( 24.0 * 60.0 * 60.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  julian_date ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Calculate Julian date
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : julianDate ( QDateTime  dt ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QDateTime  utc  =  dt . toUTC ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QDate  date  =  utc . date ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QTime  time  =  utc . time ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  julianDate ( date . year ( ) ,  date . month ( ) ,  date . day ( ) ,  time . hour ( ) ,  time . minute ( ) ,  time . second ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Get Julian date of J2000 Epoch
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : jd_j2000 ( void ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    static  double  j2000  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( j2000  = =  0.0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        j2000  =  julianDate ( 2000 ,  1 ,  1 ,  12 ,  0 ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  j2000 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Get Julian date of B1950 Epoch
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : jd_b1950 ( void ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    static  double  b1950  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( b1950  = =  0.0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        b1950  =  julianDate ( 1949 ,  12 ,  31 ,  22 ,  9 ,  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  b1950 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Get Julian date of current time Epoch
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : jd_now ( void ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    time_t  system_time ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    struct  tm  * utc_time ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Get current time in seconds since Unix Epoch (1970)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    time ( & system_time ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert to UTC (GMT)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    utc_time  =  gmtime ( & system_time ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert to Julian date
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  julianDate ( utc_time - > tm_year  +  1900 ,  utc_time - > tm_mon  +  1 ,  utc_time - > tm_mday , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                      utc_time - > tm_hour ,  utc_time - > tm_min ,  utc_time - > tm_sec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Precess a RA/DEC between two given Epochs
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								RADec  Astronomy : : precess ( RADec  rd_in ,  double  jd_from ,  double  jd_to ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    RADec  rd_out ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  x ,  y ,  z ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  xp ,  yp ,  zp ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ra_rad ,  dec_rad ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  rot [ 3 ] [ 3 ] ;       // [row][col]
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ra_deg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  days_per_century  =  36524.219878 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  t0  =  ( jd_from  -  jd_b1950 ( ) ) / days_per_century ;  // Tropical centuries since B1950.0
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  t  =  ( jd_to  -  jd_from ) / days_per_century ;      // Tropical centuries from starting epoch to ending epoch
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // From: https://www.cloudynights.com/topic/561254-ra-dec-epoch-conversion/
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 0 ] [ 0 ]  =  1.0  -  ( ( 29696.0  +  26.0 * t0 ) * t * t  -  13.0 * t * t * t ) * .00000001 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 1 ] [ 0 ]  =  ( ( 2234941.0  +  1355.0 * t0 ) * t  -  676.0 * t * t  +  221.0 * t * t * t ) * .00000001 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 2 ] [ 0 ]  =  ( ( 971690.0  -  414.0 * t0 ) * t  +  207.0 * t * t  +  96.0 * t * t * t ) * .00000001 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 0 ] [ 1 ]  =  - rot [ 1 ] [ 0 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 1 ] [ 1 ]  =  1.0  -  ( ( 24975.0  +  30.0 * t0 ) * t * t  -  15.0 * t * t * t ) * .00000001 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 2 ] [ 1 ]  =  - ( ( 10858.0  +  2.0 * t0 ) * t * t ) * .00000001 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 0 ] [ 2 ]  =  - rot [ 2 ] [ 0 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 1 ] [ 2 ]  =  rot [ 2 ] [ 1 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rot [ 2 ] [ 2 ]  =  1.0  -  ( ( 4721.0  -  4.0 * t0 ) * t * t ) * .00000001 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Hours to degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ra_deg  =  rd_in . ra * ( 360.0 / 24.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert to rectangular coordinates
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ra_rad  =  Units : : degreesToRadians ( ra_deg ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dec_rad  =  Units : : degreesToRadians ( rd_in . dec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    x  =  cos ( ra_rad )  *  cos ( dec_rad ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    y  =  sin ( ra_rad )  *  cos ( dec_rad ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    z  =  sin ( dec_rad ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Rotate
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    xp  =  rot [ 0 ] [ 0 ] * x  +  rot [ 0 ] [ 1 ] * y  +  rot [ 0 ] [ 2 ] * z ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    yp  =  rot [ 1 ] [ 0 ] * x  +  rot [ 1 ] [ 1 ] * y  +  rot [ 1 ] [ 2 ] * z ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    zp  =  rot [ 2 ] [ 0 ] * x  +  rot [ 2 ] [ 1 ] * y  +  rot [ 2 ] [ 2 ] * z ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert back to spherical coordinates
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd_out . ra  =  Units : : radiansToDegrees ( atan ( yp / xp ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( xp  <  0.0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        rd_out . ra  + =  180.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    }  else  if  ( ( yp  <  0 )  & &  ( xp  >  0 ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        rd_out . ra  + =  360.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd_out . dec  =  Units : : radiansToDegrees ( asin ( zp ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Degrees to hours
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd_out . ra  / =  ( 360.0 / 24.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  rd_out ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Calculate local mean sidereal time (LMST) in degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : localSiderealTime ( QDateTime  dateTime ,  double  longitude ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  jd  =  julianDate ( dateTime ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  d  =  ( jd  -  jd_j2000 ( ) ) ;  // Days since J2000 epoch (including fraction)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  f  =  fmod ( jd ,  1.0 ) ;  // Fractional part is decimal days
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ut  =  ( f + 0.5 ) * 24.0 ;  // Universal time in decimal hours
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // https://astronomy.stackexchange.com/questions/24859/local-sidereal-time
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // 100.46 is offset for GMST at 0h UT on 1 Jan 2000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // 0.985647 is number of degrees per day over 360 the Earth rotates in one solar day
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Approx to 0.3 arcseconds
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  fmod ( 100.46  +  0.985647  *  d  +  longitude  +  ( 360 / 24 )  *  ut ,  360.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Convert from J2000 right ascension (decimal hours) and declination (decimal degrees) to altitude and azimuth, for location (decimal degrees) and time
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								AzAlt  Astronomy : : raDecToAzAlt ( RADec  rd ,  double  latitude ,  double  longitude ,  QDateTime  dt ,  bool  j2000 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    AzAlt  aa ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ra_deg ;  // Right ascension in degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  lst_deg ;  // Local sidereal time in degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ha ;  // Hour angle
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  a ,  az ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  dec_rad ,  lat_rad ,  ha_rad ,  alt_rad ;  // Corresponding variables as radians
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  jd  =  julianDate ( dt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Precess RA/DEC from J2000 Epoch to desired (typically current) Epoch
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( j2000 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        rd  =  precess ( rd ,  jd_j2000 ( ) ,  jd ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Calculate local mean sidereal time (LMST) in degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // https://astronomy.stackexchange.com/questions/24859/local-sidereal-time
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // 100.46 is offset for GMST at 0h UT on 1 Jan 2000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // 0.985647 is number of degrees per day over 360 the Earth rotates in one solar day
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Approx to 0.3 arcseconds
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    lst_deg  =  Astronomy : : localSiderealTime ( dt ,  longitude ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert right ascension from hours to degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ra_deg  =  rd . ra  *  ( 360.0 / 24.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Calculate hour angle
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ha  =  fmod ( lst_deg  -  ra_deg ,  360.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert degrees to radians
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dec_rad  =  Units : : degreesToRadians ( rd . dec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    lat_rad  =  Units : : degreesToRadians ( latitude ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ha_rad  =  Units : : degreesToRadians ( ha ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Calculate altitude and azimuth - no correction for atmospheric refraction
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // From: http://www.convertalot.com/celestial_horizon_co-ordinates_calculator.html
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    alt_rad  =  asin ( sin ( dec_rad ) * sin ( lat_rad )  +  cos ( dec_rad ) * cos ( lat_rad ) * cos ( ha_rad ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    a  =  Units : : radiansToDegrees ( acos ( ( sin ( dec_rad ) - sin ( alt_rad ) * sin ( lat_rad ) )  /  ( cos ( alt_rad ) * cos ( lat_rad ) ) ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( sin ( ha_rad )  <  0.0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        az  =  a ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        az  =  360.0  -  a ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    aa . alt  =  Units : : radiansToDegrees ( alt_rad ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    aa . az  =  az ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  aa ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Needs to work for negative a
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : modulo ( double  a ,  double  b ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  a  -  b  *  floor ( a / b ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Calculate azimuth and altitude angles to the sun from the given latitude and longitude at the given time
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Refer to:
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// https://en.wikipedia.org/wiki/Position_of_the_Sun
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// https://www.aa.quae.nl/en/reken/zonpositie.html
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Said to be accurate to .01 degree (36") for dates between 1950 and 2050
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// although we use slightly more accurate constants and an extra term in the equation
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// of centre from the second link
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// For an alternative, see: http://www.psa.es/sdg/sunpos.htm
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Most accurate algorithm is supposedly: https://midcdmz.nrel.gov/spa/
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  Astronomy : : sunPosition ( AzAlt &  aa ,  RADec &  rd ,  double  latitude ,  double  longitude ,  QDateTime  dt ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  jd  =  julianDate ( dt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  n  =  ( jd  -  jd_j2000 ( ) ) ;  // Days since J2000 epoch (including fraction)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l  =  280.461  +  0.9856474  *  n ;  // Mean longitude of the Sun, corrected for the abberation of light
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  g  =  357.5291  +  0.98560028  *  n ;  // Mean anomaly of the Sun - how far around orbit from perihlion, in degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    l  =  modulo ( l ,  360.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    g  =  modulo ( g ,  360.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  gr  =  Units : : degreesToRadians ( g ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  la  =  l  +  1.9148  *  sin ( gr )  +  0.0200  *  sin ( 2.0 * gr )  +  0.0003  *  sin ( 3.0 * gr ) ;  // Ecliptic longitude (Ecliptic latitude b set to 0)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert la, b=0, which give the position of the Sun in the ecliptic coordinate sytem, to
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // equatorial coordinates
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  e  =  23.4393  -  3.563E-7  *  n ;  // Obliquity of the ecliptic - tilt of Earth's axis of rotation
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  er  =  Units : : degreesToRadians ( e ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  lr  =  Units : : degreesToRadians ( la ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  a  =  atan2 ( cos ( er )  *  sin ( lr ) ,  cos ( lr ) ) ;  // Right ascension, radians
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  d  =  asin ( sin ( er )  *  sin ( lr ) ) ;  // Declination, radians
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd . ra  =  modulo ( Units : : radiansToDegrees ( a ) ,  360.0 )  /  ( 360.0 / 24.0 ) ;  // Convert to hours
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd . dec  =  Units : : radiansToDegrees ( d ) ;  // Convert to degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    aa  =  raDecToAzAlt ( rd ,  latitude ,  longitude ,  dt ,  false ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : moonDays ( QDateTime  dt ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QDateTime  utc  =  dt . toUTC ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QDate  date  =  utc . date ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QTime  time  =  utc . time ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    int  y  =  date . year ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    int  m  =  date . month ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    int  D  =  date . day ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    int  d  =  367  *  y  -  7  *  ( y  +  ( m + 9 ) / 12 )  /  4  -  3  *  ( ( y  +  ( m - 9 ) / 7 )  /  100  +  1 )  /  4  +  275 * m / 9  +  D  -  730515 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  d  +  time . hour ( ) / 24.0  +  time . minute ( ) / ( 24.0 * 60.0 )  +  time . second ( ) / ( 24.0 * 60.0 * 60.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Calculate azimuth and altitude angles to the moon from the given latitude and longitude at the given time
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Refer to: https://stjarnhimlen.se/comp/ppcomp.html
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Accurate to 4 arcminute
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  Astronomy : : moonPosition ( AzAlt &  aa ,  RADec &  rd ,  double  latitude ,  double  longitude ,  QDateTime  dt ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  d  =  moonDays ( dt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ecl  =  Units : : degreesToRadians ( 23.4393  -  3.563E-7  *  d ) ;  // Obliquity of the ecliptic - tilt of Earth's axis of rotation
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Orbital elements for the Sun
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ws  =  Units : : degreesToRadians ( 282.9404  +  4.70935E-5  *  d ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  Ms  =  Units : : degreesToRadians ( 356.0470  +  0.9856002585  *  d ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Orbital elements for the Moon
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  Nm  =  Units : : degreesToRadians ( 125.1228  -  0.0529538083  *  d ) ;            // longitude of the ascending node
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  im  =  Units : : degreesToRadians ( 5.1454 ) ;                                 // inclination to the ecliptic (plane of the Earth's orbit)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  wm  =  Units : : degreesToRadians ( 318.0634  +  0.1643573223  *  d ) ;            // argument of perihelion
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  am  =  60.2666 ;                                                          // (Earth radii) semi-major axis, or mean distance from Sun
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  em  =  0.054900 ;       // ecm                                                 // eccentricity (0=circle, 0-1=ellipse, 1=parabola)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  Mm  =  Units : : degreesToRadians ( 115.3654  +  13.0649929509  *  d ) ;           // mean anomaly (0 at perihelion; increases uniformly with time), degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  Em  =  Mm  +  em  *  sin ( Mm )  *  ( 1.0  +  em  *  cos ( Mm ) ) ;  // Eccentric anomaly in radians
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  xv  =  am  *  ( cos ( Em )  -  em ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  yv  =  am  *  ( sqrt ( 1.0  -  em * em )  *  sin ( Em ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  vm  =  atan2 ( yv ,  xv ) ;  // True anomaly
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  rm  =  sqrt ( xv * xv  +  yv * yv ) ;  // Distance
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Compute position in space (for the Moon, this is geocentric)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  xh  =  rm  *  ( cos ( Nm )  *  cos ( vm + wm )  -  sin ( Nm )  *  sin ( vm + wm )  *  cos ( im ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  yh  =  rm  *  ( sin ( Nm )  *  cos ( vm + wm )  +  cos ( Nm )  *  sin ( vm + wm )  *  cos ( im ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  zh  =  rm  *  ( sin ( vm + wm )  *  sin ( im ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert to ecliptic longitude and latitude
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  lonecl  =  atan2 ( yh ,  xh ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  latecl  =  atan2 ( zh ,  sqrt ( xh * xh + yh * yh ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Perturbations of the Moon
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  Ls  =  Ms  +  ws ;                 // Mean Longitude of the Sun  (Ns=0)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  Lm  =  Mm  +  wm  +  Nm ;            // Mean longitude of the Moon
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  D  =  Lm  -  Ls ;                  // Mean elongation of the Moon
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  F  =  Lm  -  Nm ;                  // Argument of latitude for the Moon
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  dlon ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  =  - 1.274  *  sin ( Mm  -  2 * D ) ;            // (the Evection)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  + 0.658  *  sin ( 2 * D ) ;                // (the Variation)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  - 0.186  *  sin ( Ms ) ;                 // (the Yearly Equation)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  - 0.059  *  sin ( 2 * Mm  -  2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  - 0.057  *  sin ( Mm  -  2 * D  +  Ms ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  + 0.053  *  sin ( Mm  +  2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  + 0.046  *  sin ( 2 * D  -  Ms ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  + 0.041  *  sin ( Mm  -  Ms ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  - 0.035  *  sin ( D ) ;                  // (the Parallactic Equation)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  - 0.031  *  sin ( Mm  +  Ms ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  - 0.015  *  sin ( 2 * F  -  2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlon  + =  + 0.011  *  sin ( Mm  -  4 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  dlat ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlat  =  - 0.173  *  sin ( F  -  2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlat  + =  - 0.055  *  sin ( Mm  -  F  -  2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlat  + =  - 0.046  *  sin ( Mm  +  F  -  2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlat  + =  + 0.033  *  sin ( F  +  2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dlat  + =  + 0.017  *  sin ( 2 * Mm  +  F ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    lonecl  + =  Units : : degreesToRadians ( dlon ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    latecl  + =  Units : : degreesToRadians ( dlat ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rm  + =  - 0.58  *  cos ( Mm  -  2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rm  + =  - 0.46  *  cos ( 2 * D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert perturbed
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    xh  =  rm  *  cos ( lonecl )  *  cos ( latecl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    yh  =  rm  *  sin ( lonecl )  *  cos ( latecl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    zh  =  rm                *  sin ( latecl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert to geocentric coordinates (already the case for the Moon)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  xg  =  xh ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  yg  =  yh ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  zg  =  zh ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert to equatorial cordinates
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  xe  =  xg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ye  =  yg  *  cos ( ecl )  -  zg  *  sin ( ecl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ze  =  yg  *  sin ( ecl )  +  zg  *  cos ( ecl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Compute right ascension and declination
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ra  =  atan2 ( ye ,  xe ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  dec  =  atan2 ( ze ,  sqrt ( xe * xe + ye * ye ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd . ra  =  modulo ( Units : : radiansToDegrees ( ra ) ,  360.0 )  /  ( 360.0 / 24.0 ) ;  // Convert to hours
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd . dec  =  Units : : radiansToDegrees ( dec ) ;  // Convert to degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert from geocentric to topocentric
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  mpar  =  asin ( 1 / rm ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  lat  =  Units : : degreesToRadians ( latitude ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  gclat  =  Units : : degreesToRadians ( latitude  -  0.1924  *  sin ( 2.0  *  lat ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  rho  =  0.99833  +  0.00167  *  cos ( 2 * lat ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QTime  time  =  dt . toUTC ( ) . time ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  UT  =  time . hour ( )  +  time . minute ( ) / 60.0  +  time . second ( ) / ( 60.0 * 60.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  GMST0  =  Units : : radiansToDegrees ( Ls ) / 15.0  +  12 ;  // In hours
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  GMST  =  GMST0  +  UT ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  LST  =  GMST  +  longitude / 15.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  HA  =  Units : : degreesToRadians ( LST * 15.0  -  Units : : radiansToDegrees ( ra ) ) ;     // Hour angle in radians
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  g  =  atan ( tan ( gclat )  /  cos ( HA ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  topRA  =  ra  -  mpar  *  rho  *  cos ( gclat )  *  sin ( HA )  /  cos ( dec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  topDec ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( g  ! =  0.0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        topDec  =  dec  -  mpar  *  rho  *  sin ( gclat )  *  sin ( g  -  dec )  /  sin ( g ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        topDec  =  dec  -  mpar  *  rho  *  sin ( - dec )  *  cos ( HA ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd . ra  =  modulo ( Units : : radiansToDegrees ( topRA ) ,  360.0 )  /  ( 360.0 / 24.0 ) ;  // Convert to hours
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rd . dec  =  Units : : radiansToDegrees ( topDec ) ;  // Convert to degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    aa  =  raDecToAzAlt ( rd ,  latitude ,  longitude ,  dt ,  false ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Calculated adjustment to altitude angle from true to apparent due to atmospheric refraction using
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Saemundsson's formula (which is used by Stellarium and is primarily just for
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// optical wavelengths)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// See: https://en.wikipedia.org/wiki/Atmospheric_refraction#Calculating_refraction
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Alt is in degrees. 90 = Zenith gives a factor of 0.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Pressure in millibars
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Temperature in Celsuis
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// We divide by 60.0 to get a value in degrees (as original formula is in arcminutes)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : refractionSaemundsson ( double  alt ,  double  pressure ,  double  temperature ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  pt  =  ( pressure / 1010.0 )  *  ( 283.0 / ( 273.0 + temperature ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-13 23:03:55 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    return  pt  *  ( 1.02  /  tan ( Units : : degreesToRadians ( alt + 10.3 / ( alt + 5.11 ) ) )  +  0.0019279 )  /  60.0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-01-13 20:51:38 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Calculated adjustment to altitude angle from true to apparent due to atmospheric refraction using
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// code from Starlink Positional Astronomy Library. This is more accurate for
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// radio than Saemundsson's formula, but also more complex.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// See: https://github.com/Starlink/pal
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Alt is in degrees. 90 = Zenith gives a factor of 0.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Pressure in millibars
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Temperature in Celsuis
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Humdity in %
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Frequency in Hertz
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Latitude in decimal degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// HeightAboveSeaLevel in metres
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Temperature lapse rate in K/km
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : refractionPAL ( double  alt ,  double  pressure ,  double  temperature ,  double  humidity ,  double  frequency , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                                double  latitude ,  double  heightAboveSeaLevel ,  double  temperatureLapseRate ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  tdk  =  Units : : celsiusToKelvin ( temperature ) ;    // Ambient temperature at the observer (K)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  wl  =  ( 299792458.0 / frequency ) * 1000000.0 ;       // Wavelength in micrometres
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  rh  =  humidity / 100.0 ;                          // Relative humidity in range 0-1
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  phi  =  Units : : degreesToRadians ( latitude ) ;      // Latitude of the observer (radian, astronomical)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  tlr  =  temperatureLapseRate / 1000.0 ;            // Temperature lapse rate in the troposphere (K/metre)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  refa ,  refb ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  z  =  90.0 - alt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  zu  =  Units : : degreesToRadians ( z ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  zr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    palRefco ( heightAboveSeaLevel ,  tdk ,  pressure ,  rh , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                wl ,  phi ,  tlr ,  1E-10 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                & refa ,  & refb ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    palRefz ( zu ,  refa ,  refb ,  & zr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  z - Units : : radiansToDegrees ( zr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : raToDecimal ( const  QString &  value ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QRegExp  decimal ( " ^([0-9]+( \\ .[0-9]+) ? ) " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QRegExp  hms ( " ^([0-9]+) [  h ] ( [ 0 - 9 ] + ) [  m ] ( [ 0 - 9 ] + ( \ \ . [ 0 - 9 ] + ) ? ) s ? " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( decimal . exactMatch ( value ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  decimal . capturedTexts ( ) [ 0 ] . toDouble ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    else  if  ( hms . exactMatch ( value ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  Units : : hoursMinutesSecondsToDecimal ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    hms . capturedTexts ( ) [ 1 ] . toDouble ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    hms . capturedTexts ( ) [ 2 ] . toDouble ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    hms . capturedTexts ( ) [ 3 ] . toDouble ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : decToDecimal ( const  QString &  value ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QRegExp  decimal ( " ^(-?[0-9]+( \\ .[0-9]+) ? ) " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    QRegExp  dms ( QString ( " ^(-?[0-9]+) [  % 1 d ] ( [ 0 - 9 ] + ) [  ' m ] ( [ 0 - 9 ] + ( \ \ . [ 0 - 9 ] + ) ? ) [ \ " s]? " ) . arg ( QChar ( 0xb0 ) ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( decimal . exactMatch ( value ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  decimal . capturedTexts ( ) [ 0 ] . toDouble ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    else  if  ( dms . exactMatch ( value ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  Units : : degreesMinutesSecondsToDecimal ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    dms . capturedTexts ( ) [ 1 ] . toDouble ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    dms . capturedTexts ( ) [ 2 ] . toDouble ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    dms . capturedTexts ( ) [ 3 ] . toDouble ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  Astronomy : : lstAndRAToLongitude ( double  lst ,  double  raHours ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  longitude  =  lst  -  ( raHours  *  15.0 ) ;  // Convert hours to degrees
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( longitude  <  - 180.0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        longitude  + =  360.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    else  if  ( longitude  >  180.0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        longitude  - =  360.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  - longitude ;  // East positive
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-29 12:57:58 +00:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								// Return right ascension and declination of North Galactic Pole in J2000 Epoch
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  Astronomy : : northGalacticPoleJ2000 ( double &  ra ,  double &  dec ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ra  =  12  +  51.4  /  60.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    dec  =  27.13 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Convert from equatorial to Galactic coordinates, J2000 Epoch
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  Astronomy : : equatorialToGalactic ( double  ra ,  double  dec ,  double &  l ,  double &  b ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    const  double  raRad  =  Units : : degreesToRadians ( ra  *  15.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    const  double  decRad  =  Units : : degreesToRadians ( dec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Calculate RA and dec for North Galactic pole, J2000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  ngpRa ,  ngpDec ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    northGalacticPoleJ2000 ( ngpRa ,  ngpDec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    const  double  ngpRaRad  =  Units : : degreesToRadians ( ngpRa  *  15.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    const  double  ngpDecRad  =  Units : : degreesToRadians ( ngpDec ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Calculate galactic latitude for North Celestial pole, J2000
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    const  double  ncpLRad  =  Units : : degreesToRadians ( 122.93192 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Calculate galactic longitude in radians
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  bRad  =  asin ( sin ( ngpDecRad ) * sin ( decRad ) + cos ( ngpDecRad ) * cos ( decRad ) * cos ( raRad  -  ngpRaRad ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Find the two possible solutions for galactic longitude in radians
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  rhs1  =  cos ( decRad ) * sin ( raRad - ngpRaRad ) / cos ( bRad ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  rhs2  =  ( - cos ( decRad ) * sin ( ngpDecRad ) * cos ( raRad - ngpRaRad ) + sin ( decRad ) * cos ( ngpDecRad ) ) / cos ( bRad ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l1  =  ncpLRad  -  asin ( rhs1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l2  =  ncpLRad  -  acos ( rhs2 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Plug them back in and select solution which is valid for both equations
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // (Error should be 0, but we have to allow for small numerical differences)
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // There's probably a better way to solve this.
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l1lhs1  =  sin ( ncpLRad  -  l1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l1lhs2  =  cos ( ncpLRad  -  l1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l2lhs1  =  sin ( ncpLRad  -  l2 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l2lhs2  =  cos ( ncpLRad  -  l2 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l1Diff  =  abs ( l1lhs1  -  rhs1 )  +  abs ( l1lhs2  -  rhs2 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  l2Diff  =  abs ( l2lhs1  -  rhs1 )  +  abs ( l2lhs2  -  rhs2 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    double  lRad ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( l1Diff  <  l2Diff ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        lRad  =  l1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        lRad  =  l2 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    // Convert to degrees in range -90,90 and 0,360
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    b  =  Units : : radiansToDegrees ( bRad ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    l  =  Units : : radiansToDegrees ( lRad ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( l  <  0.0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        l  + =  360.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( l  >  360.0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        l  - =  360.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-01-13 20:51:38 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								// The following functions are from Starlink Positional Astronomy Library
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// https://github.com/Starlink/pal
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Pi */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  const  double  PAL__DPI  =  3.1415926535897932384626433832795028841971693993751 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* 2Pi */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  const  double  PAL__D2PI  =  6.2831853071795864769252867665590057683943387987502 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* pi/180:  degrees to radians */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  const  double  PAL__DD2R  =  0.017453292519943295769236907684886127134428718885417 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* Radians to degrees */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  const  double  PAL__DR2D  =  57.295779513082320876798154814105170332405472466564 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* DMAX(A,B) - return maximum value - evaluates arguments multiple times */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# define DMAX(A,B) ((A) > (B) ? (A) : (B) ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								/* DMIN(A,B) - return minimum value - evaluates arguments multiple times */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# define DMIN(A,B) ((A) < (B) ? (A) : (B) ) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Normalize angle into range +/- pi
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								double  palDrange (  double  angle  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   double  result  =  fmod (  angle ,  PAL__D2PI  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   if (  result  >  PAL__DPI  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      result  - =  PAL__D2PI ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   }  else  if (  result  <  - PAL__DPI  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      result  + =  PAL__D2PI ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   return  result ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								//  Calculate stratosphere parameters
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  pal1Atms  (  double  rt ,  double  tt ,  double  dnt ,  double  gamal , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                double  r ,  double  *  dn ,  double  *  rdndr  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  b ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  w ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  b  =  gamal  /  tt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  w  =  ( dnt  -  1.0 )  *  exp (  - b  *  ( r - rt )  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * dn  =  1.0  +  w ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * rdndr  =  - r  *  b  *  w ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Calculate troposphere parameters
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  pal1Atmt  (  double  r0 ,  double  t0 ,  double  alpha ,  double  gamm2 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                double  delm2 ,  double  c1 ,  double  c2 ,  double  c3 ,  double  c4 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                double  c5 ,  double  c6 ,  double  r , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                double  * t ,  double  * dn ,  double  * rdndr  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  tt0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  tt0gm2 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  tt0dm2 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * t  =  DMAX (  DMIN (  t0  -  alpha * ( r - r0 ) ,  320.0 ) ,  100.0  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tt0  =  * t  /  t0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tt0gm2  =  pow (  tt0 ,  gamm2  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tt0dm2  =  pow (  tt0 ,  delm2  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * dn  =  1.0  +  (  c1  *  tt0gm2  -  (  c2  -  c5  /  * t  )  *  tt0dm2  )  *  tt0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * rdndr  =  r  *  (  - c3  *  tt0gm2  +  (  c4  -  c6  /  tt0  )  *  tt0dm2  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Adjust unrefracted zenith distance
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  palRefz  (  double  zu ,  double  refa ,  double  refb ,  double  * zr  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /* Constants */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /* Largest usable ZD (deg) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  D93  =  93.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /* ZD at which one model hands over to the other (radians) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  Z83  =  83.0  *  PAL__DD2R ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /* coefficients for high ZD model (used beyond ZD 83 deg) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  C1  =  + 0.55445 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  C2  =  - 0.01133 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  C3  =  + 0.00202 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  C4  =  + 0.28385 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  C5  =  + 0.02390 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /* High-ZD-model prefiction (deg) for that point */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  REF83  =  ( C1 + C2 * 7.0 + C3 * 49.0 ) / ( 1.0 + C4 * 7.0 + C5 * 49.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  zu1 , zl , s , c , t , tsq , tcu , ref , e , e2 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  perform calculations for zu or 83 deg, whichever is smaller */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  zu1  =  DMIN ( zu , Z83 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  functions of ZD */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  zl  =  zu1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  s  =  sin ( zl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  c  =  cos ( zl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  t  =  s / c ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tsq  =  t * t ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tcu  =  t * tsq ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  refracted zd (mathematically to better than 1 mas at 70 deg) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  zl  =  zl - ( refa * t + refb * tcu ) / ( 1.0 + ( refa + 3.0 * refb * tsq ) / ( c * c ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  further iteration */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  s  =  sin ( zl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  c  =  cos ( zl ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  t  =  s / c ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tsq  =  t * t ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tcu  =  t * tsq ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ref  =  zu1 - zl + 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ( zl - zu1 + refa * t + refb * tcu ) / ( 1.0 + ( refa + 3.0 * refb * tsq ) / ( c * c ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  special handling for large zu */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( zu  >  zu1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    e  =  90.0 - DMIN ( D93 , zu * PAL__DR2D ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    e2  =  e * e ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ref  =  ( ref / REF83 ) * ( C1 + C2 * e + C3 * e2 ) / ( 1.0 + C4 * e + C5 * e2 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  return refracted zd */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * zr  =  zu - ref ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Determine constants in atmospheric refraction model
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  palRefco  (  double  hm ,  double  tdk ,  double  pmb ,  double  rh , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                double  wl ,  double  phi ,  double  tlr ,  double  eps , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                double  * refa ,  double  * refb  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  r1 ,  r2 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Sample zenith distances: arctan(1) and arctan(4) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  ATN1  =  0.7853981633974483 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  ATN4  =  1.325817663668033 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Determine refraction for the two sample zenith distances */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  palRefro ( ATN1 , hm , tdk , pmb , rh , wl , phi , tlr , eps , & r1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  palRefro ( ATN4 , hm , tdk , pmb , rh , wl , phi , tlr , eps , & r2 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Solve for refraction constants */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * refa  =  ( 64.0 * r1 - r2 ) / 60.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * refb  =  ( r2 - 4.0 * r1 ) / 60.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								// Atmospheric refraction for radio and optical/IR wavelengths
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								static  void  palRefro (  double  zobs ,  double  hm ,  double  tdk ,  double  pmb , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								               double  rh ,  double  wl ,  double  phi ,  double  tlr , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								               double  eps ,  double  *  ref  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   *   Fixed  parameters 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  93 degrees in radians */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  D93  =  1.623156204 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Universal gas constant */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  GCR  =  8314.32 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Molecular weight of dry air */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  DMD  =  28.9644 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Molecular weight of water vapour */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  DMW  =  18.0152 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Mean Earth radius (metre) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  S  =  6378120. ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Exponent of temperature dependence of water vapour pressure */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  DELTA  =  18.36 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Height of tropopause (metre) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  HT  =  11000. ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Upper limit for refractive effects (metre) */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  double  HS  =  80000. ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Numerical integration: maximum number of strips. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  const  int  ISMAX = 16384l ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /* Local variables */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  int  is ,  k ,  n ,  i ,  j ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  int  optic ,  loop ;  /* booleans */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  double  zobs1 , zobs2 , hmok , tdkok , pmbok , rhok , wlok , alpha , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    tol , wlsq , gb , a , gamal , gamma , gamm2 , delm2 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    tdc , psat , pwo , w , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    c1 , c2 , c3 , c4 , c5 , c6 , r0 , tempo , dn0 , rdndr0 , sk0 , f0 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rt , tt , dnt , rdndrt , sine , zt , ft , dnts , rdndrp , zts , fts , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    rs , dns , rdndrs , zs , fs , refold , z0 , zrange , fb , ff , fo , fe , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    h , r , sz , rg , dr , tg , dn , rdndr , t , f , refp , reft ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  The refraction integrand */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# define refi(DN,RDNDR) RDNDR / (DN+RDNDR) 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  Transform ZOBS into the normal range. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  zobs1  =  palDrange ( zobs ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  zobs2  =  DMIN ( fabs ( zobs1 ) , D93 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  keep other arguments within safe bounds. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  hmok  =  DMIN ( DMAX ( hm , - 1e3 ) , HS ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tdkok  =  DMIN ( DMAX ( tdk , 100.0 ) , 500.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pmbok  =  DMIN ( DMAX ( pmb , 0.0 ) , 10000.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  rhok  =  DMIN ( DMAX ( rh , 0.0 ) , 1.0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  wlok  =  DMAX ( wl , 0.1 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  alpha  =  DMIN ( DMAX ( fabs ( tlr ) , 0.001 ) , 0.01 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  tolerance for iteration. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tol  =  DMIN ( DMAX ( fabs ( eps ) , 1e-12 ) , 0.1 ) / 2.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  decide whether optical/ir or radio case - switch at 100 microns. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  optic  =  wlok  <  100.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  set up model atmosphere parameters defined at the observer. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  wlsq  =  wlok * wlok ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  gb  =  9.784 * ( 1.0 - 0.0026 * cos ( phi + phi ) - 0.00000028 * hmok ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( optic )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    a  =  ( 287.6155 + ( 1.62887 + 0.01360 / wlsq ) / wlsq )  *  273.15e-6 / 1013.25 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    a  =  77.6890e-6 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  gamal  =  ( gb * DMD ) / GCR ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  gamma  =  gamal / alpha ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  gamm2  =  gamma - 2.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  delm2  =  DELTA - 2.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  tdc  =  tdkok - 273.15 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  psat  =  pow ( 10.0 , ( 0.7859 + 0.03477 * tdc ) / ( 1.0 + 0.00412 * tdc ) )  * 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    ( 1.0 + pmbok * ( 4.5e-6 + 6.0e-10 * tdc * tdc ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( pmbok  >  0.0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pwo  =  rhok * psat / ( 1.0 - ( 1.0 - rhok ) * psat / pmbok ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    pwo  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  w  =  pwo * ( 1.0 - DMW / DMD ) * gamma / ( DELTA - gamma ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  c1  =  a * ( pmbok + w ) / tdkok ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( optic )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    c2  =  ( a * w + 11.2684e-6 * pwo ) / tdkok ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    c2  =  ( a * w + 6.3938e-6 * pwo ) / tdkok ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  c3  =  ( gamma - 1.0 ) * alpha * c1 / tdkok ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  c4  =  ( DELTA - 1.0 ) * alpha * c2 / tdkok ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( optic )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    c5  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    c6  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    c5  =  375463e-6 * pwo / tdkok ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    c6  =  c5 * delm2 * alpha / ( tdkok * tdkok ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  conditions at the observer. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  r0  =  S + hmok ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pal1Atmt ( r0 , tdkok , alpha , gamm2 , delm2 , c1 , c2 , c3 , c4 , c5 , c6 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								           r0 , & tempo , & dn0 , & rdndr0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  sk0  =  dn0 * r0 * sin ( zobs2 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  f0  =  refi ( dn0 , rdndr0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  conditions in the troposphere at the tropopause. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  rt  =  S + DMAX ( HT , hmok ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pal1Atmt ( r0 , tdkok , alpha , gamm2 , delm2 , c1 , c2 , c3 , c4 , c5 , c6 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								           rt , & tt , & dnt , & rdndrt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  sine  =  sk0 / ( rt * dnt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  zt  =  atan2 ( sine , sqrt ( DMAX ( 1.0 - sine * sine , 0.0 ) ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  ft  =  refi ( dnt , rdndrt ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  conditions in the stratosphere at the tropopause. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pal1Atms ( rt , tt , dnt , gamal , rt , & dnts , & rdndrp ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  sine  =  sk0 / ( rt * dnts ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  zts  =  atan2 ( sine , sqrt ( DMAX ( 1.0 - sine * sine , 0.0 ) ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  fts  =  refi ( dnts , rdndrp ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  conditions at the stratosphere limit. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  rs  =  S + HS ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  pal1Atms ( rt , tt , dnt , gamal , rs , & dns , & rdndrs ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  sine  =  sk0 / ( rs * dns ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  zs  =  atan2 ( sine , sqrt ( DMAX ( 1.0 - sine * sine , 0.0 ) ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  fs  =  refi ( dns , rdndrs ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  variable initialization to avoid compiler warning. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  reft  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  integrate the refraction integral in two parts;  first in the
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								   *   troposphere  ( k = 1 ) ,  then  in  the  stratosphere  ( k = 2 ) .  */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  for  ( k = 1 ;  k < = 2 ;  k + + )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /*     initialize previous refraction to ensure at least two iterations. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    refold  =  1.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /*     start off with 8 strips. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    is  =  8 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /*     start z, z range, and start and end values. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( k = = 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      z0  =  zobs2 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      zrange  =  zt - z0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      fb  =  f0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      ff  =  ft ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      z0  =  zts ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      zrange  =  zs - z0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      fb  =  fts ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      ff  =  fs ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /*     sums of odd and even values. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    fo  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    fe  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /*     first time through the loop we have to do every point. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    n  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /*     start of iteration loop (terminates at specified precision). */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    loop  =  1 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    while  ( loop )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      /*        strip width. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      h  =  zrange / ( ( double ) is ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      /*        initialize distance from earth centre for quadrature pass. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  ( k  = =  1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        r  =  r0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        r  =  rt ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      /*        one pass (no need to compute evens after first time). */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      for  ( i = 1 ;  i < is ;  i + = n )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								              /*           sine of observed zenith distance. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        sz  =  sin ( z0 + h * ( double ) ( i ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           find r (to the nearest metre, maximum four iterations). */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  ( sz  >  1e-20 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          w  =  sk0 / sz ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          rg  =  r ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          dr  =  1.0e6 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          j  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          while  (  fabs ( dr )  >  1.0  & &  j  <  4  )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            j + + ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if  ( k = = 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								              pal1Atmt ( r0 , tdkok , alpha , gamm2 , delm2 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                       c1 , c2 , c3 , c4 , c5 , c6 , rg , & tg , & dn , & rdndr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								              pal1Atms ( rt , tt , dnt , gamal , rg , & dn , & rdndr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            dr  =  ( rg * dn - w ) / ( dn + rdndr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            rg  =  rg - dr ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          r  =  rg ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           find the refractive index and integrand at r. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  ( k = = 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          pal1Atmt ( r0 , tdkok , alpha , gamm2 , delm2 , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                   c1 , c2 , c3 , c4 , c5 , c6 , r , & t , & dn , & rdndr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          pal1Atms ( rt , tt , dnt , gamal , r , & dn , & rdndr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        f  =  refi ( dn , rdndr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           accumulate odd and (first time only) even values. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  ( n = = 1  & &  i % 2  = =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          fe  + =  f ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								          fo  + =  f ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      /*        evaluate the integrand using simpson's rule. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      refp  =  h * ( fb + 4.0 * fo + 2.0 * fe + ff ) / 3.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      /*        has the required precision been achieved (or can't be)? */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      if  ( fabs ( refp - refold )  >  tol  & &  is  <  ISMAX )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           no: prepare for next iteration.*/ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           save current value for convergence test. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        refold  =  refp ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           double the number of strips. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        is  + =  is ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           sum of all current values = sum of next pass's even values. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        fe  + =  fo ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           prepare for new odd values. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        fo  =  0.0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           skip even values next time. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        n  =  2 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /*           yes: save troposphere component and terminate the loop. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  ( k = = 1 )  reft  =  refp ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        loop  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  /*  result. */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  * ref  =  reft + refp ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								  if  ( zobs1  <  0.0 )  * ref  =  - ( * ref ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								}