Beispiel #1
0
double DLL_FUNC jpl_get_constant( const int idx, void *ephem, char *constant_name)
{
   struct jpl_eph_data *eph = (struct jpl_eph_data *)ephem;
   double rval = 0.;

   *constant_name = '\0';
   if( idx >= 0 && idx < (int)eph->ncon)
      {
      const long seek_loc = (idx < 400 ? 84L * 3L + (long)idx * 6 :
                      START_400TH_CONSTANT_NAME + (idx - 400) * 6);

      fseek( eph->ifile, seek_loc, SEEK_SET);
      if( fread( constant_name, 1, 6, eph->ifile))
         {
         constant_name[6] = '\0';
         fseek( eph->ifile, eph->recsize + (long)idx * sizeof( double), SEEK_SET);
         if( fread( &rval, 1, sizeof( double), eph->ifile))
            if( eph->swap_bytes)     /* gotta swap the constants,  too */
               swap_64_bit_val( &rval, 1);
         }
      }
   return( rval);
}
Beispiel #2
0
void * DLL_FUNC jpl_init_ephemeris(const char *ephemeris_filename,
                          char nam[][6], double *val)
{
    unsigned i, j;
    long de_version;
    char title[84];
    FILE *ifile = fopen(ephemeris_filename, "rb");

    struct jpl_eph_data *rval;
    struct jpl_eph_data temp_data;

    init_err_code = 0;
    temp_data.ifile = ifile;
    if(!ifile)
      init_err_code = JPL_INIT_FILE_NOT_FOUND;
    else if(fread(title, 84, 1, ifile) != 1)
      init_err_code = JPL_INIT_FREAD_FAILED;
    else if(FSeek(ifile, 2652L, SEEK_SET))
      init_err_code = JPL_INIT_FSEEK_FAILED;
    else if(fread(&temp_data, JPL_HEADER_SIZE, 1, ifile) != 1)
      init_err_code = JPL_INIT_FREAD2_FAILED;

    if(init_err_code)
    {
      if(ifile)
        fclose(ifile);
      return(NULL);
    }

    de_version = atoi(title + 26);
    
    /* A small piece of trickery:  in the binary file,  data is stored */
    /* for ipt[0...11],  then the ephemeris version,  then the         */
    /* remaining ipt[12] data.  A little switching is required to get  */
    /* the correct order. */
    temp_data.ipt[12][0] = temp_data.ipt[12][1];
    temp_data.ipt[12][1] = temp_data.ipt[12][2];
    temp_data.ipt[12][2] = temp_data.ipt[13][0];
    temp_data.ephemeris_version = de_version;

    //qDebug() << "DE_Version: " << de_version;


    temp_data.swap_bytes = (temp_data.ncon > 65536L);
    if(temp_data.swap_bytes)     /* byte order is wrong for current platform */
    {
      qDebug() << "Byte order is wrong for current platform";
      
      swap_64_bit_val(&temp_data.ephem_start, 1);
      swap_64_bit_val(&temp_data.ephem_end, 1);
      swap_64_bit_val(&temp_data.ephem_step, 1);
      swap_32_bit_val(&temp_data.ncon);
      swap_64_bit_val(&temp_data.au, 1);
      swap_64_bit_val(&temp_data.emrat, 1);
    }

            /* It's a little tricky to tell if an ephemeris really has  */
            /* TT-TDB data (with offsets in ipt[13][] and ipt[14][]).   */
            /* Essentially,  we read the data and sanity-check it,  and */
            /* zero it if it "doesn't add up" correctly.                */
            /*    Also:  certain ephems I've generated with ncon capped */
            /* at 400 have no TT-TDB data.  So if ncon == 400,  don't   */
            /* try to read such data;  you may get garbage.             */
    if(de_version >= 430 && temp_data.ncon != 400)
    {
         /* If there are 400 or fewer constants,  data for ipt[13][0...2] */
         /* immediately follows that for ipt[12][0..2];  i.e.,  we don't  */
         /* need to fseek().  Otherwise,  we gotta skip 6*(n_constants-400) */
         /* bytes. */
      if(temp_data.ncon > 400)
	 FSeek(ifile, (size_t)(temp_data.ncon - 400) * 6, SEEK_CUR);
      if(fread(&temp_data.ipt[13][0], sizeof(int32_t), 6, ifile) != 6)
         init_err_code = JPL_INIT_FREAD5_FAILED;
    }
    else                 /* mark header data as invalid */
      temp_data.ipt[13][0] = (uint32_t)-1;

    if(temp_data.swap_bytes)     /* byte order is wrong for current platform */
    {  
        for(j = 0; j < 3; j++)
        {
            for(i = 0; i < 15; i++)
            { 
                swap_32_bit_val(&temp_data.ipt[i][j]);
            }
        }
    }

    if(temp_data.ipt[13][0] !=       /* if these don't add up correctly, */
          temp_data.ipt[12][0] + temp_data.ipt[12][1] * temp_data.ipt[12][2] * 3
    || temp_data.ipt[14][0] !=       /* zero them out (they've garbage data) */
          temp_data.ipt[13][0] + temp_data.ipt[13][1] * temp_data.ipt[13][2] * 3)
    {     /* not valid pointers to TT-TDB data */
      memset(&temp_data.ipt[13][0], 0, 6 * sizeof(int32_t));
    }

         /* A sanity check:  if the earth-moon ratio is outside reasonable */
         /* bounds,  we must be looking at a wrong or corrupted file.      */
         /* In DE-102,  emrat = 81.3007;  in DE-405/406, emrat = 81.30056. */
         /* Those are the low and high ranges.  We'll allow some slop in   */
         /* case the earth/moon mass ratio changes:                        */
    if(temp_data.emrat > 81.3008 || temp_data.emrat < 81.30055)
    {   
      init_err_code = JPL_INIT_FILE_CORRUPT;
      qWarning() << "temp_data: " << temp_data.emrat << "(should have been =~81). JPL_INIT_FILE_CORRUPT!";
    }

    if(init_err_code)
    {
      fclose(ifile);
      return(NULL);
    }

         /* Once upon a time,  the kernel size was determined from the */
         /* DE version.  This was not a terrible idea,  except that it */
         /* meant that when the code faced a new version,  it broke.   */
         /* Now we use some logic to compute the kernel size.          */
    temp_data.kernel_size = 4;
    for(i = 0; i < 15; i++)
      temp_data.kernel_size +=
             2 * temp_data.ipt[i][1] * temp_data.ipt[i][2] * dimension(i);
// for(i = 0; i < 13; i++)
//    temp_data.kernel_size +=
//                     temp_data.ipt[i][1] * temp_data.ipt[i][2] * ((i == 11) ? 4 : 6);
//       /* ...and then add in space required for the TT-TDB data : */
// temp_data.kernel_size += temp_data.ipt[14][1] * temp_data.ipt[14][2] * 2;
    temp_data.recsize = temp_data.kernel_size * 4L;
    temp_data.ncoeff = temp_data.kernel_size / 2L;

               /* Rather than do two separate allocations,  everything     */
               /* we need is allocated in _one_ chunk,  then parceled out. */
               /* This looks a little weird,  but it simplifies error      */
               /* handling and cleanup.                                    */
    rval = (struct jpl_eph_data *)calloc(sizeof(struct jpl_eph_data)
                        + temp_data.recsize, 1);
    if(!rval)
    {
      init_err_code = JPL_INIT_MEMORY_FAILURE;
      fclose(ifile);
      return(NULL);
    }
    memcpy(rval, &temp_data, sizeof(struct jpl_eph_data));
    rval->iinfo.posn_coeff[0] = 1.0;
            /* Seed a bogus value here.  The first and subsequent calls to */
            /* 'interp' will correct it to a value between -1 and +1.      */
    rval->iinfo.posn_coeff[1] = -2.0;
    rval->iinfo.vel_coeff[0] = 0.0;
    rval->iinfo.vel_coeff[1] = 1.0;
    rval->curr_cache_loc = (uint32_t)-1;
    
              /* The 'cache' data is right after the 'jpl_eph_data' struct: */
    rval->cache = (double *)(rval + 1);
               /* If there are more than 400 constants,  the names of       */
               /* the extra constants are stored in what would normally     */
               /* be zero-padding after the header record.  However,        */
               /* older ephemeris-reading software won't know about that.   */
               /* So we store ncon=400,  then actually check the names to   */
               /* see how many constants there _really_ are.  Older readers */
               /* will just see 400 names and won't know about the others.  */
               /* But on the upside, they won't crash.                      */

    if(rval->ncon == 400)
    {
      char buff[7];

      buff[6] = '\0';
      FSeek(ifile, START_400TH_CONSTANT_NAME, SEEK_SET);
      while(fread(buff, 6, 1, ifile) && strlen(buff) == 6)
      {
         rval->ncon++;
      }
    }

    if(val)
    {
      FSeek(ifile, rval->recsize, SEEK_SET);
      if(fread(val, sizeof(double), (size_t)rval->ncon, ifile)
                        != (size_t)rval->ncon)
         init_err_code = JPL_INIT_FREAD3_FAILED;
      else if(rval->swap_bytes)     /* gotta swap the constants,  too */
         swap_64_bit_val(val, rval->ncon);
      }

   if(!init_err_code && nam)
      {
      FSeek(ifile, 84L * 3L, SEEK_SET);   /* just after the 3 'title' lines */
      for(i = 0; i < rval->ncon && !init_err_code; i++)
      {
        if(i == 400)
	  FSeek(ifile, START_400TH_CONSTANT_NAME, SEEK_SET);
        if(fread(nam[i], 6, 1, ifile) != 1)
          init_err_code = JPL_INIT_FREAD4_FAILED;
        }
      }
  return(rval);
}
Beispiel #3
0
/*****************************************************************************
**                        jpl_state(ephem,et2,list,pv,nut,bary)             **
******************************************************************************
** This subroutine reads and interpolates the jpl planetary ephemeris file  **
**                                                                          **
**    Calling sequence parameters:                                          **
**                                                                          **
**    Input:                                                                **
**                                                                          **
**        et2[] double, 2-element JED epoch at which interpolation          **
**              is wanted.  Any combination of et2[0]+et2[1] which falls    **
**              within the time span on the file is a permissible epoch.    **
**                                                                          **
**               a. for ease in programming, the user may put the           **
**                  entire epoch in et2[0] and set et2[1]=0.0               **
**                                                                          **
**               b. for maximum interpolation accuracy, set et2[0] =        **
**                  the most recent midnight at or before interpolation     **
**                  epoch and set et2[1] = fractional part of a day         **
**                  elapsed between et2[0] and epoch.                       **
**                                                                          **
**               c. as an alternative, it may prove convenient to set       **
**                  et2[0] = some fixed epoch, such as start of integration,**
**                  and et2[1] = elapsed interval between then and epoch.   **
**                                                                          **
**       list   13-element integer array specifying what interpolation      **
**              is wanted for each of the "bodies" on the file.             **
**                                                                          **
**                        list[i]=0, no interpolation for body i            **
**                               =1, position only                          **
**                               =2, position and velocity                  **
**                                                                          **
**              the designation of the astronomical bodies by i is:         **
**                                                                          **
**                        i = 0: mercury                                    **
**                          = 1: venus                                      **
**                          = 2: earth-moon barycenter                      **
**                          = 3: mars                                       **
**                          = 4: jupiter                                    **
**                          = 5: saturn                                     **
**                          = 6: uranus                                     **
**                          = 7: neptune                                    **
**                          = 8: pluto                                      **
**                          = 9: geocentric moon                            **
**                          =10: nutations in lon & obliq (if on file)      **
**                          =11: lunar librations (if on file)              **
**                          =12: lunar mantle omegas                        **
**                          =13: TT-TDB (if on file)                        **
**                                                                          **
** Note that I've not actually seen case 12 yet.  It probably doesn't work. **
**                                                                          **
**    output:                                                               **
**                                                                          **
**    pv[][6]   double array that will contain requested interpolated       **
**              quantities.  The body specified by list[i] will have its    **
**              state in the array starting at pv[i][0]  (on any given      **
**              call, only those words in 'pv' which are affected by the    **
**              first 10 'list' entries (and by list(11) if librations are  **
**              on the file) are set.  The rest of the 'pv' array           **
**              is untouched.)  The order of components in pv[][] is:       **
**              pv[][0]=x,....pv[][5]=dz.                                   **
**                                                                          **
**              All output vectors are referenced to the earth mean         **
**              equator and equinox of epoch. The moon state is always      **
**              geocentric; the other nine states are either heliocentric   **
**              or solar-system barycentric, depending on the setting of    **
**              global variables (see below).                               **
**                                                                          **
**              Lunar librations, if on file, are put into pv[10][k] if     **
**              list[11] is 1 or 2.                                         **
**                                                                          **
**        nut   dp 4-word array that will contain nutations and rates,      **
**              depending on the setting of list[10].  the order of         **
**              quantities in nut is:                                       **
**                                                                          **
**                       d psi  (nutation in longitude)                     **
**                       d epsilon (nutation in obliquity)                  **
**                       d psi dot                                          **
**                       d epsilon dot                                      **
**                                                                          **
*****************************************************************************/
int DLL_FUNC jpl_state(void *ephem, const double et, const int list[14],
                          double pv[][6], double nut[4], const int bary)
{
  struct jpl_eph_data *eph = (struct jpl_eph_data *)ephem;
  unsigned i, j, n_intervals;
  uint32_t nr;
  double *buf = eph->cache;
  double t[2];
  const double block_loc = (et - eph->ephem_start) / eph->ephem_step;
  bool recompute_pvsun;
  const double aufac = 1.0 / eph->au;

/*   error return for epoch out of range  */
  if(et < eph->ephem_start || et > eph->ephem_end)
    return(JPL_EPH_OUTSIDE_RANGE);

/*   calculate record # and relative time in interval   */

  nr = (uint32_t)block_loc;
  t[0] = block_loc - (double)nr;
  if(!t[0] && nr)
  {
    t[0] = 1.;
    nr--;
  }  

/*   read correct record if not in core (static vector buf[])   */
    if(nr != eph->curr_cache_loc)
    {
      eph->curr_cache_loc = nr;
                  /* Read two blocks ahead to account for header: */
      if(FSeek(eph->ifile, (nr + 2) * eph->recsize, SEEK_SET))
      {
	      // GZ: Make sure we will try again on next call...
	      eph->curr_cache_loc=0;
	      return(JPL_EPH_FSEEK_ERROR);
      }
      if(fread(buf, sizeof(double), (size_t)eph->ncoeff, eph->ifile)
                               != (size_t)eph->ncoeff)
        return(JPL_EPH_READ_ERROR);

      if(eph->swap_bytes)
         swap_64_bit_val(buf, eph->ncoeff);
      }
    t[1] = eph->ephem_step;

    if(eph->pvsun_t != et)   /* If several calls are made for the same et, */
    {                      /* don't recompute pvsun each time... only on */
      recompute_pvsun = true;   /* the first run through.                     */
      eph->pvsun_t = et;
    }
    else
      recompute_pvsun = false;

          /* Here, i loops through the "traditional" 14 listed items -- 10
          solar system objects,  nutations,  librations,  lunar mantle angles,
          and TT-TDT -- plus a fifteenth:  the solar system barycenter.  That
          last is quite different:  it's computed 'as needed',  rather than
          from list[];  the output goes to pvsun rather than the pv array;
          and three quantities (position,  velocity,  acceleration) are
          computed (nobody else gets accelerations at present.)  */
  for(n_intervals = 1; n_intervals <= 8; n_intervals *= 2)
    for(i = 0; i < 15; i++)
    {
        unsigned quantities;
        uint32_t *iptr = &eph->ipt[i + 1][0];

        if(i == 14)
        {
            quantities = (recompute_pvsun ? 3 : 0);
            iptr = &eph->ipt[10][0];
          }
          else
          {
            quantities = list[i];
            iptr = &eph->ipt[i < 10 ? i : i + 1][0];
          }
          if(n_intervals == iptr[2] && quantities)
          {
            double *dest = ((i == 10) ? eph->pvsun : pv[i]);

            if(i < 10)
               dest = pv[i];
            else if(i == 14)
               dest = eph->pvsun;
            else
               dest = nut;
            interp(&eph->iinfo, &buf[iptr[0]-1], t, (int)iptr[1],
                                    dimension(i + 1),
                                    n_intervals, quantities, dest);

            if(i < 10 || i == 14)        /*  convert km to AU */
               for(j = 0; j < quantities * 3; j++)
                  dest[j] *= aufac;
            }
         }
    if(!bary)                             /* gotta correct everybody for */
      for(i = 0; i < 9; i++)            /* the solar system barycenter */
         for(j = 0; j < (unsigned)list[i] * 3; j++)
            pv[i][j] -= eph->pvsun[j];
    return(0);
}