(file) Return to dsdsmigr.c CVS log (file) (dir) Up to [Development] / JSOC / proj / dsdsmigr / libs

File: [Development] / JSOC / proj / dsdsmigr / libs / dsdsmigr.c (download)
Revision: 1.1, Wed Jan 12 01:26:36 2011 UTC (12 years, 4 months ago) by arta
Branch: MAIN
CVS Tags: Ver_LATEST, Ver_9-5, Ver_9-41, Ver_9-4, Ver_9-3, Ver_9-2, Ver_9-1, Ver_9-0, Ver_8-8, Ver_8-7, Ver_8-6, Ver_8-5, Ver_8-4, Ver_8-3, Ver_8-2, Ver_8-12, Ver_8-11, Ver_8-10, Ver_8-1, Ver_8-0, Ver_7-1, Ver_7-0, Ver_6-4, Ver_6-3, Ver_6-2, Ver_6-1, Ver_6-0, Ver_5-14, Ver_5-13, HEAD
Add ephemeris functions to a library, dsdsmigr.a, and in set_gaps_missing_test, add the setting of ephemeris keywords by linking to libdsdsmigr.a

#include <math.h>
#include <stdio.h>
#include <sys/stat.h>
#include "timeio.h"

/*
 * ecanom calculates the eccentric anomaly from the mean anomaly
 * and the eccentricity of date.  The method used is sufficient
 * applications of Newton's method to the equation (c.f. SA p. 117)
 *
 *	E - M - eps * sin( E ) = 0
 *
 * where E is the eccentric anomaly and M is the mean anomaly. The
 * diagnostic counter and message can be removed when this has be
 * thoroughly tested.
 */

#define EPS 3.e-17
static double ecanom (double e, double manom) {
  int i;
  double ecm_new, ecm_old;

  ecm_old = manom + e*sin(manom);    /* first approximation */
  i = 0;	/* diagnostic counter */
  for (;;) {
	++i;
	ecm_new = ecm_old - (ecm_old - manom - e * sin( ecm_old)) /
			(1 - e * cos( ecm_old));
	if (fabs((ecm_new - ecm_old)/(ecm_new + ecm_old)) < EPS ||
	  fabs((ecm_new - ecm_old)) < EPS ) break;
	ecm_old = ecm_new;
    if (i > 16) {
      fprintf (stderr, "ecanom: excessive iterations: %d\nold,new", i);
      fprintf (stderr, " %g %g %g\n", ecm_old, ecm_new, ecm_new-ecm_old);
      break;
    }
  }
  return (ecm_new);
}

#define EPHEM_OFFSET	(-11865398400.0) /*  (sscan_time ("1601.01.01_00:00:00"))  */

#define EPHEM_SIZE	35	/* size of array to declare for solephem etc. */

#define EPHEM_T		1	/* time used for calculations		*/
#define EPHEM_TCENT	2	/* time in centuries since 1900.0	*/
#define EPHEM_JD	3	/* time as Julian date			*/
#define EPHEM_ST	4	/* sidereal time			*/
#define EPHEM_RA	5	/* right ascention (geometric)		*/
#define EPHEM_DEC	6	/* declination (geometric)		*/
#define EPHEM_CLONG	7	/* geometric longitude			*/
#define EPHEM_L0	8	/* carrington degrees of central point of disk */
#define EPHEM_B0	9	/* latitude of central point of disk	*/
#define EPHEM_P		10	/* position angle of northern extremity of rotation */
				/* axis. + to east from north (in sky)	*/
#define EPHEM_DIST	11	/* true distance to sun (AU)		*/
#define EPHEM_RSUN	12	/* true semi-diameter of sun (arc-sec)	*/
#define EPHEM_VEARTH	13	/* angular velocity of earth (m/s)	*/
#define EPHEM_EOT	14	/* equation of time			*/
#define EPHEM_B0V	15	/* b0 wobble (m per s)			*/
#define EPHEM_PHI	16	/* phi = aux angle for deltav		*/
#define EPHEM_SINP	17	/* sin(p)				*/
#define EPHEM_COSP	18	/* cos(p)				*/
#define EPHEM_PAROT	19	/* pa of rotation axis wrt ecliptic     */
				  /*  the following defined in delta_v  */
#define EPHEM_RHO	20	/* rho					*/
#define EPHEM_L		21	/* Longitude on disk			*/
#define EPHEM_B		22	/* heliographic latitude		*/
#define EPHEM_R		23	/* r/Rsun				*/
#define EPHEM_SECZ	24	/* 1/cos(zentih angle)			*/
#define EPHEM_SINL	25	/* sin(L)				*/
#define EPHEM_SINB	26	/* sin(B)				*/
				   /*  the following defined in deltaI  */
#define EPHEM_IA	27	/* I/I_zenith				*/
#define EPHEM_LD	28	/* I/I_center - limb darkening 5250	*/
#define EPHEM_AIRM	29	/* airmass				*/
#define EPHEM_DV	30	/* deltav				*/
			    /*  the following defined in sun_ephemeris  */
#define EPHEM_OBS_LON	31	/* Observer longitude			*/
#define EPHEM_OBS_LAT	32	/* Observer latitude			*/
				     /*  following used in mdi_point()  */

static void solephem (double time, double *ephem) {
/*
  This procedure finds the ephemerides for the sun at the time "time".
  several quantities are computed and returned in the array ephem
  These quantities are (except as noted) the same as found in the
  American Ephemeris and Nautical Almanac (AENA).  See that document and
  the Explanatory Supplement to the Astronomical Ephemeris and the American
  Ephemeris and Nautical Almanac (ESAEAENA - 1973 edition) as well as         
  Smart "Textbook on Spherical Astronomy" (SA) for the methods used.
  all angles (including sideral time) in radians.  Note that ephem is
  assumed to point to 19 doubles of storage.
  ephem[1]:	 time used for computation 
	2:	 t = time in centuries of 36525 days since 1900.0
	3:	 jd = Julian date
	4:	 st = siderial time (nearest 0 UT)
	5:	 ra = right ascention (geometric)
	6:	 dec = declination (geometric)
	7:	 clong = geometric longitude
	8:	 l0 = carrington degrees of central point of disk
	9:	 b0 = latitude of central point of disk
       10:	 p = position angle of northern extremity of rotation
			axis. + to east from north (in sky)
       11:	 r = true distance to sun (AU)[
       12:	 rsun = true semi-diameter of sun (arc-sec)
		 uncorrected for irradiance (c.f. AENA p. 541) 
       13:	 vearth = angular velocity of earth * 1 AU. (m/s)
       14:	 eot = equation of time
       15:	 b0 wobble (m per s)
       16:	 phi = aux angle for deltav
       17:	 sin(p)
       18:	 cos(p)
       19:       position angle of Sun wrt the ecliptic

	In some AENA formulae, seemingly superfluous digits are the result
	of the use of the AENA numbers given in degrees, minutes and seconds
	and converted to radians with a full double precision representation
	of pi.

	Note that because of the AENA formulae used, some of the numbers do
	not make sense if a time before the middle of the 20th century is given.

	References to SA are to 6th edition (1977) and to AENA the 1979 issue.
	Adapted and modified from version on rc4000 - josh

  **    References to Green are to "Spherical Astronomy", l985, by RM
	Green.     11/86  rob
			*/

  double dwork1, dwork2, dsd;
  long year,modsd,ly,sd,doy;
  double tenths,tenths_sid_mean,tt;
  double days_1900,t,mean_sid_time,hams,rams,ra,lo,eot,pi,two_pi,
	clong,omega,xx,xs,xc,cosclo,b0,l0,l00,perigee,e,rday,
	clong_omega,p,r,rsun,sinincl,cosincl,tanincl,
	sinb0,dec,g,ge,v,eps,y;


/* note that internally some calculations are performed in tenths of seconds.
 * the origin of this is an older definition of time used on a previous
 * machine - when you know all about it, you fix it
 */

	/* constants, rday is radians per tenth of second */

  pi=3.14159265358979324;
  two_pi=6.28318530717995865;
  rday=two_pi/864000;
/* sine, cosine and tangent of the inclination of the sun's rotation axis to 
 * the ecliptic - all those digits are flourish - 7.25 degrees, AENA, p. 553
 */
	sinincl = 0.126198969135829761;
	cosincl = 0.992004949679714999;
	tanincl = 0.127216068001046929;
/* tenths of seconds in UT day and UT day number from 1601 */
/*  Assume times refer to old baseline; the explicit correction is not made  */
/*
  time -= sscan_time ("1601.01.01_00:00:00");
*/
	tenths = modf((double)time/86400.0, &dsd);
	sd = dsd;
	tenths *= 864000.0;
/* year and day of year - for carrington degrees */
	modf((double)sd/36524.0, &dwork1);
	modf((double)sd/146096.0, &dwork2);
	modsd = (long)(sd + dwork1 - dwork2);
	ly=modsd/1461;
	dwork1 = (modsd+1-1461*ly)/365.3;
	if(dwork1 < 0)
		{
		modf(fabs(dwork1), &dwork1);
		dwork1 = -1.0 - dwork1;
		}
	else
		modf(dwork1, &dwork1);
	year=4*ly+dwork1;
	modf((double)(year*365.25), &dwork1);
	doy= modsd + 1 - dwork1;
	year=1601+year;
/* days since 1900, and the unit of time used for AENA formulae, t,
 * the time in Julian centuries of 36525 mean solar days from Greenwich
 * mean noon (12h UT) on 1900 January 0 (AENA p. 528).
 * t is an integer # days + 0.5 (for calculation of quantities at 0h UT
 * on the current date) and tt is the current time.
 */
	days_1900=dsd-109206.0-0.5;
/* 109206.0 = atodate("1899:12:31:0:0:0")/86400.0 */
	t=days_1900/36525.0;
	tt = t + tenths/(864000.0*36525.0);
/* eccentricity of earth's orbit (AENA p. 540) */
	e = 0.01675104 - tt*(4.18e-5 + 1.26e-7*tt);
/* mean obliquity of the ecliptic (AENA p. 540) */
	eps = 0.40931975520272993 - tt*(2.271109689158e-4 +
		tt*(2.86040072e-8 - tt*8.7751276e-9));
/* mean longitude of perigee, mean equinox of date (AENA p. 539) */
	perigee=4.90822946686888692 + tt*( 3.000526416797e-2 +
		tt*( 7.9024630021e-6 + tt*5.81776417e-8));
/* geometric mean longitude, mean equinox of date (AENA p. 539) */
	lo = 4.8815279341118791 + tt*(628.33195094248177 + 5.2796209873e-6*tt);
/* where did all these ^ sig. figures come from?   rob */
/* y, used in calculation of right ascension (ra) */
	y = tan( (double)(eps/2.0) );
	y = y*y;
/* siderial time in tenths of seconds (AENA p. 528) */
	tenths_sid_mean=239258.36+86401845.42*t+
				0.929*t*t+1.0027379093*tenths;
/* mean sideral time within day in radians */
	mean_sid_time = two_pi*modf(tenths_sid_mean/864000.0, &dwork2);
/* hams is the hour angle of the mean sun */
	hams=(tenths-432000.0)*rday; if(  hams < 0  ) hams=hams+two_pi;
/* rams is the right ascension of the mean sun */
	rams=mean_sid_time-hams; if(  rams < 0  ) rams=rams+two_pi;
/* mean anomaly - (c.f. AENA p. 540) */
	g = lo - perigee;
/* eccentric anomaly, mean equinox of date */
	ge = ecanom(e, g);
/* true anomaly, mean equinox of date (SA p. 118) */
	v = 2.0*atan(sqrt((1.0+e)/(1.0-e))*tan(0.5*ge));
/* geometric longitude, mean equinox of date  (Green p 253) */
	clong = v + perigee;
	if(clong > two_pi)clong -= two_pi;
	  else if (clong < 0)clong += two_pi;
/* right ascension, mean equinox of date (SA p. 148) */
	ra = atan2( (1.0-y)*sin(clong),(1+y)*cos(clong));
	if(ra < 0)ra += two_pi;
/* equation of time */
	eot = rams - ra;
	if(eot > pi)eot -= two_pi;
	  else if(eot < -pi)eot += two_pi;
/* declination (SA p. 40) */
	dec = asin(sin(eps)*sin(clong));
/* longitude of ascending node of solar equator on ecliptic (AENA p. 553) */
      omega=1.2857258823024895+2.436188747575e-4*(time-7857648000.0)/3.15576e7;
/* 7,857,648,000 = atodate("1850:1:1:0:0:0") */
	clong_omega=clong-omega;
	if( clong_omega < 0 )
		clong_omega= clong_omega+two_pi;
	  else if( clong_omega >= two_pi)
		clong_omega= clong_omega-two_pi;
	xs=sin(clong_omega); xc= cos(clong_omega);
	cosclo = xc= cos(clong_omega);
/* heliocentric latitude of center of disk, ESAEAENA p. 308   */
	sinb0= xs*sinincl;
	b0 = asin(sinb0);
/* heliocentric longitude of the center of the disk ESAEAENA p. 308
 * currently used to correct older version below.
 */
	l00 = atan2(-xs*cosincl,-xc)+5.1097298952004202 + 0.247564432906997103
	  * (2430000.5 - 2415020.0 - days_1900 - (tenths/864000.0));
	l00 = modf(l00/two_pi, &dwork1);
	l00 *= two_pi;
	if(l00 < 0)l00 += two_pi;
	xx = xc * sinincl;
/*
to within 0.25 degrees, or 4 arc-sec, (i.e. ignore inclination
  of the solar equator) carrington degrees is degrees sun has
  rotated since 1854.0 + degrees before 1854.0 (==720) - degrees
  earth has moved in its orbit since 1854.0 + omega
  calculated in rotations, then converted to degrees
*/
	l0= (time - 7983921600.0)/(25.38*86400.0)
/* 7,983,921,600 = atodate("1854:1:1:12:0:0") */
		 + 2.5 - clong_omega/two_pi - (year-1854);
	if(  doy>90  && clong>omega  ) l0=l0-1;
/* refine to account for the inclination of the sun's rotation axis */
	dwork1 = l0;
	modf(l0, &l0);
	l0 = l0 + (two_pi - l00)/two_pi;
/* correct for possible error due to truncation of l0 at Carr Rot boundary */
	if (dwork1 - l0 > 0.9) l0 = l0 + 1.0;
	else if (l0 - dwork1 > 0.9) l0 = l0 - 1.0;
/* position angle of the northern extremity of the axis of rotation
 * measured eastward from the north point of the disk, ESAEAENA p. 309 
 */
	p=atan(-tan(eps)*cos(clong))+atan(-tanincl*xc);
	xc=cos(clong-perigee);
	r=(1.0-e*e)/(1.0+e*xc);
	rsun=959.63/r;

  ephem[EPHEM_T] = time;
  ephem[EPHEM_TCENT] = t;
  ephem[EPHEM_JD] = 2415020.0 + days_1900;
  ephem[EPHEM_ST] = mean_sid_time;
  ephem[EPHEM_RA] = ra;
  ephem[EPHEM_DEC] = dec;
  ephem[EPHEM_CLONG] = clong;
  ephem[EPHEM_L0] = l0*360;
  ephem[EPHEM_B0] = b0;
  ephem[EPHEM_P] = p;
  ephem[EPHEM_DIST] = r;
  ephem[EPHEM_RSUN] = rsun;
  ephem[EPHEM_VEARTH] = 29785.9*(1+e*xc);
		       /*  1.496e11 * two_pi / 3.155692597474e7 = 29786.31454  */
			  /*  This is consistent with 1 AU = 1.4959792e13 cm  */
  ephem[EPHEM_EOT] = eot;
/*
					original formula prior to 2004.01.29
  ephem[EPHEM_B0V] = xx * ephem[EPHEM_RSUN] / 1.496e11;
		formula in /home/soi/src/libastro.d/solephem.c as of 2004.01.29
  ephem[EPHEM_B0V] = -xx * sin (ephem[EPHEM_RSUN]*pi/(3600*180.0)) * 1.496e11 *
      two_pi / (365.2425*86400);
*/
  ephem[EPHEM_B0V] = xx * ephem[EPHEM_VEARTH];
  ephem[EPHEM_PHI] = atan (0.4336*cos(clong)+p);
  ephem[EPHEM_SINP] = sin (p);
  ephem[EPHEM_COSP] = cos (p);
  ephem[EPHEM_PAROT] = atan (-tanincl*cosclo);
  return;
}

static void calc_sun_ephemeris (TIME time, double ephem[], double obs_lon, double obs_lat) {
  solephem (time - EPHEM_OFFSET, ephem);
  ephem[EPHEM_OBS_LON] = obs_lon * M_PI / 180.0;
  ephem[EPHEM_OBS_LAT] = obs_lat * M_PI / 180.0;
}

static int sds_flip (void *data, long length, int size) {
  long i,j;
  char *c, t;
  unsigned short *s;
  unsigned int *l;
  
  if (data == NULL) return 1;

  if (size == 2) {
    s = (unsigned short *)data;
    for (i=0; i<length; i++, s++) *s = (*s<<8) | (*s>>8);
  } else if (size == 4) {
    l = (unsigned int *)data;
    for (i=0; i<length; i++, l++)
      *l = (*l<<24) | ((*l&0xff00)<<8) | ((*l&0xff0000)>>8) | (*l>>24);
  } else {
    c = (char *)data;
    for (i=0; i<length; i++, c+=size)
      for (j=0; j<(size/2); j++) {
	t = *(c+j);
	*(c+j) = *(c+size-j-1);
	*(c+size-j-1) = t;
      }
  }

  return 0;
}

#define SUMMARY_FILE	("/home/soi/CM/tables/ephemeris/summary")
#define TABLE_DT    (600.0)
#define SUMMARY_REC (6)

int soho_ephemeris (TIME obs_time, double *r, double *b, double *l,
    double *vr, double *vn, double *vw, TIME *table_mod_time) {
/*
 *  Interpolate heliocentric position-velocity vector in summary SOHO orbit
 *    table
 *
 *  Bugs:
 *    For times outside the bounds of table, or if table is unreadable,
 *      earth (L0L0) ephemeris is returned,
 *    Times during coverage gaps return all 0 for ephemeris parameters, this
 *	is how gaps are signaled
 *    Leaves file open for possible next use.
 */
  static FILE *sumfile = NULL;
  static int firstcall = 1;
  static TIME tab_start, tab_stop;
  struct stat stat_buf;
  double obs_vel0[SUMMARY_REC], obs_vel1[SUMMARY_REC];
  double dt, f0, f1;
  int gap = 0, offset, reclen = SUMMARY_REC * sizeof (double);

  if (firstcall) {
    stat (SUMMARY_FILE, &stat_buf);
    *table_mod_time = stat_buf.st_mtime + UNIX_EPOCH;
    sumfile = fopen (SUMMARY_FILE, "r");
    if (sumfile) {
      fread (&tab_start, sizeof (TIME), 1, sumfile);
      fread (&tab_stop, sizeof (TIME), 1, sumfile);
#if __BYTE_ORDER == __LITTLE_ENDIAN
      sds_flip ((void *)&tab_start, 1, sizeof (TIME));
      sds_flip ((void *)&tab_stop, 1, sizeof (TIME));
#endif
    }
    firstcall = 0;
  }
    
  if (!sumfile || obs_time < tab_start || obs_time > (tab_stop + TABLE_DT)) {
    double p1, p2;
    double ephem[EPHEM_SIZE];
    calc_sun_ephemeris (obs_time, ephem, 0.0, 0.0);
    *r = 0.99 * ephem[EPHEM_DIST];
    *l = 360.0 - fmod (ephem[EPHEM_L0], 360.0);
    *b = ephem[EPHEM_B0] * 180.0 / M_PI;
    *vw = ephem[EPHEM_VEARTH];
    *vn = ephem[EPHEM_B0V];
    calc_sun_ephemeris (obs_time - 1.0e5, ephem, 0.0, 0.0);
    p1 = ephem[EPHEM_DIST];
    calc_sun_ephemeris (obs_time + 1.0e5, ephem, 0.0, 0.0);
    p2 = ephem[EPHEM_DIST];
    *vr = (1.496e11)*(p2 - p1)/2.0e5;
    return (sumfile ? -1 : -2);
  }
  if (obs_time >= tab_stop) {
    gap = 1;
    fseek (sumfile, -reclen, SEEK_END);
    fread (obs_vel0, sizeof (double), SUMMARY_REC, sumfile);
#if __BYTE_ORDER == __LITTLE_ENDIAN
    sds_flip ((void *)obs_vel0, SUMMARY_REC, sizeof (double));
#endif
    *vw = obs_vel0[4];
    *vn = obs_vel0[5];
    *r = obs_vel0[0];
    *vr = obs_vel0[3];
    *b = obs_vel0[2];
    *l = obs_vel0[1];
    return gap;
  }
  offset = reclen * floor ((obs_time - tab_start) / TABLE_DT) + 
    2 * sizeof (TIME);
  fseek (sumfile, offset, SEEK_SET);
  fread (obs_vel0, sizeof (double), SUMMARY_REC, sumfile);
  fread (obs_vel1, sizeof (double), SUMMARY_REC, sumfile);
#if __BYTE_ORDER == __LITTLE_ENDIAN
  sds_flip ((void *)obs_vel0, SUMMARY_REC, sizeof (double));
  sds_flip ((void *)obs_vel1, SUMMARY_REC, sizeof (double));
#endif
  dt = fmod ((obs_time - tab_start), TABLE_DT) / TABLE_DT;
  f1 = dt; f0 = 1.0 - f1;
  *r = f0 * obs_vel0[0] + f1 * obs_vel1[0];
  while (obs_vel1[1] > obs_vel0[1]) obs_vel1[1] -= 360.0;
  *l = f0 * obs_vel0[1] + f1 * obs_vel1[1];
  while (*l < 0.0) *l += 360.0;
  *b = f0 * obs_vel0[2] + f1 * obs_vel1[2];
  *vr = f0 * obs_vel0[3] + f1 * obs_vel1[3];
  *vw = f0 * obs_vel0[4] + f1 * obs_vel1[4];
  *vn = f0 * obs_vel0[5] + f1 * obs_vel1[5];
  if (*r < 0.1) gap = 2;
  return gap;
}

Karen Tian
Powered by
ViewCVS 0.9.4