int
main( void )
{
  static LALStatus status;

  char eEphFileBad[] = TEST_DATA_DIR "earth47.dat";
  char eEphFile[] = TEST_DATA_DIR "earth98.dat";
  char sEphFile[] = TEST_DATA_DIR "sun98.dat";

  /* Checking response if data files not present */
  EphemerisData edat;
  edat.ephiles.earthEphemeris = eEphFileBad;
  edat.ephiles.sunEphemeris   = sEphFile;
  LALInitBarycenter(&status, &edat);
  if ( status.statusCode != LALINITBARYCENTERH_EOPEN)
    {
      XLALPrintError( "Got error code %d and message '%s', but expected error code %d\n", status.statusCode, status.statusDescription, LALINITBARYCENTERH_EOPEN);
      return LALBARYCENTERTESTC_EOPEN;
    }
  else
    {
      // XLALPrintError ("==================== this error is as expected and OK!! ==================== \n");
      xlalErrno = 0;
    }

  /* Now inputting kosher ephemeris. files and leap sec, to illustrate
   * proper usage. The real, serious TEST of the code is a script written
   * by Rejean Dupuis comparing LALBarycenter to TEMPO for thousands
   * of source positions and times.
   */
  edat.ephiles.earthEphemeris = eEphFile;
  edat.ephiles.sunEphemeris = sEphFile;
  LALInitBarycenter(&status, &edat);
  if ( status.statusCode ) {
    XLALPrintError ("LALInitBarycenter() failed with code %d\n", status.statusCode);
    return XLAL_EFAILED;
  }

  /* ===== now test equivalence of new XLALInitBarycenter() function ========== */
  EphemerisData *edat_xlal;
  if ( ( edat_xlal = XLALInitBarycenter ( eEphFile, sEphFile )) == NULL ) {
    XLALPrintError ("Something failed in XLALInitBarycenter(), errno =%d\n", xlalErrno );
    return XLAL_EFAILED;
  }
  if ( compare_ephemeris ( &edat, edat_xlal ) != XLAL_SUCCESS ) {
    XLALPrintError ("Equivalence test failed between XLALInitEphemeris() and LALInitEphemeris()\n" );
    return XLAL_EFAILED;
  }
  XLALDestroyEphemerisData ( edat_xlal );

  /* ========================================================================== */


 /* The routines using LALBarycenter package, the code above, leading
    up LALInitBarycenter call, should be near top of main. The idea is
    that ephemeris data is read into RAM once, at the beginning.

    NOTE that the only part of the piece of the LALDetector structure
    baryinput.site that has to be filled in by the driver code is
    the 3-vector: baryinput.site.location[] .

    NOTE that the driver code that calls LALInitBarycenter must
    LALFree(edat->ephemE) and LALFree(edat->ephemS).
    The driver code that calls LALBarycenter must LALFree(edat).
 */

  /* Now getting coords for detector */
  LALDetector cachedDetector;
  cachedDetector = lalCachedDetectors[LALDetectorIndexGEO600DIFF];

  BarycenterInput XLAL_INIT_DECL(baryinput);
  baryinput.site.location[0]=cachedDetector.location[0]/LAL_C_SI;
  baryinput.site.location[1]=cachedDetector.location[1]/LAL_C_SI;
  baryinput.site.location[2]=cachedDetector.location[2]/LAL_C_SI;

  EarthState earth;
  EarthState earth_xlal;
  EmissionTime  emit, emit_xlal, emit_opt;

  /* ----- Checking error messages when the timestamp is not within the 1-yr ephemeris files */
  LIGOTimeGPS tGPS = {t1998+5e7, 0 };
  LALBarycenterEarth ( &status, &earth, &tGPS, &edat );
  if ( status.statusCode == 0 ) {
    XLALPrintError ( "LALBarycenterEarth() succeeded but expected to get error\n");
    return LALBARYCENTERTESTC_EOUTOFRANGEE;
  } else {
    XLALPrintError ("==================== this error is as expected and OK!! ==================== \n");
    xlalErrno = 0;
  }

  /* next try calling for bad choice of RA,DEC (e.g., something sensible in degrees, but radians)*/
  tGPS.gpsSeconds = t1998+3600;
  LALBarycenterEarth ( &status, &earth, &tGPS, &edat );

  baryinput.alpha= 120;
  baryinput.delta = 60;
  baryinput.dInv = 0;

  LALBarycenter ( &status, &emit, &baryinput, &earth );
  if ( status.statusCode == 0 ) {
    XLALPrintError( "LALBarycenter() succeeded but expected to get error\n" );
    return LALBARYCENTERTESTC_EBADSOURCEPOS;
  } else {
    XLALPrintError ("==================== this error is as expected and OK!! ==================== \n");
    xlalErrno = 0;
  }

  /* ---------- Now running program w/o errors, to illustrate proper use. ---------- */
  EmissionTime XLAL_INIT_DECL(maxDiff);
  EmissionTime XLAL_INIT_DECL(maxDiffOpt);
  REAL8 tic, toc;
  UINT4 NRepeat = 1;
  UINT4 counter = 0;
  REAL8 tau_lal = 0, tau_xlal = 0, tau_opt = 0;
  BarycenterBuffer *buffer = NULL;

  unsigned int seed = XLALGetTimeOfDay();
  srand ( seed );

  /* Outer loop over different sky positions */
  for ( UINT4 k=0; k < 300; k++)
    {
      baryinput.alpha = ( 1.0 * rand() / RAND_MAX ) * LAL_TWOPI;	// in [0, 2pi]
      baryinput.delta = ( 1.0 * rand() / RAND_MAX ) * LAL_PI - LAL_PI_2;// in [-pi/2, pi/2]
      baryinput.dInv = 0.e0;

      /* inner loop over pulse arrival times */
      for ( UINT4 i=0; i < 100; i++ )
        {
          REAL8 tPulse = t1998 + ( 1.0 * rand() / RAND_MAX ) * LAL_YRSID_SI;	// t in [1998, 1999]
          XLALGPSSetREAL8( &tGPS, tPulse );
          baryinput.tgps = tGPS;

          /* ----- old LAL interface ---------- */
          LALBarycenterEarth ( &status, &earth, &tGPS, &edat);
          if ( status.statusCode ) {
            XLALPrintError ("LALBarycenterEarth() failed with code %d\n", status.statusCode);
            return XLAL_EFAILED;
          }

          tic = XLALGetTimeOfDay();
          for ( UINT4 l = 0; l < NRepeat; l++ )
            LALBarycenter ( &status, &emit, &baryinput, &earth );
          toc = XLALGetTimeOfDay();
          tau_lal += ( toc - tic ) / NRepeat;
          if ( status.statusCode ) {
            XLALPrintError ("LALBarycenter() failed with code %d\n", status.statusCode);
            return XLAL_EFAILED;
          }

          /* ----- new XLAL interface ---------- */
          XLAL_CHECK ( XLALBarycenterEarth ( &earth_xlal, &tGPS, &edat ) == XLAL_SUCCESS, XLAL_EFAILED );
          tic = XLALGetTimeOfDay();
          for ( UINT4 l = 0; l < NRepeat; l ++ )
            XLAL_CHECK ( XLALBarycenter ( &emit_xlal, &baryinput, &earth_xlal ) == XLAL_SUCCESS, XLAL_EFAILED );
          toc = XLALGetTimeOfDay();
          tau_xlal += ( toc - tic ) / NRepeat;

          /* collect maximal deviations over all struct-fields of 'emit' */
          EmissionTime thisDiff;
          diffEmissionTime ( &thisDiff, &emit, &emit_xlal );
          absmaxEmissionTime ( &maxDiff, &maxDiff, &thisDiff );

          /* ----- optimized XLAL version with buffering ---------- */
          tic = XLALGetTimeOfDay();
          for ( UINT4 l = 0; l < NRepeat; l ++ )
            XLAL_CHECK ( XLALBarycenterOpt ( &emit_opt, &baryinput, &earth_xlal, &buffer ) == XLAL_SUCCESS, XLAL_EFAILED );
          toc = XLALGetTimeOfDay();
          tau_opt += ( toc - tic ) / NRepeat;

          /* collect maximal deviations over all struct-fields of 'emit' */
          diffEmissionTime ( &thisDiff, &emit, &emit_opt );
          absmaxEmissionTime ( &maxDiffOpt, &maxDiffOpt, &thisDiff );

          counter ++;
        } /* for i */

    } /* for k */

  XLALFree ( buffer );
  buffer = NULL;

  /* ----- check differences in results ---------- */
  REAL8 tolerance = 1e-9;	// in seconds: can't go beyond nanosecond precision due to GPS limitation
  REAL8 maxEmitDiff = maxErrInEmissionTime ( &maxDiff );
  REAL8 maxEmitDiffOpt = maxErrInEmissionTime ( &maxDiffOpt );
  XLALPrintInfo ( "Max error (in seconds) between LALBarycenter() and XLALBarycenter()     = %g s (tolerance = %g s)\n", maxEmitDiff, tolerance );
  XLAL_CHECK ( maxEmitDiff < tolerance, XLAL_EFAILED,
               "Max error (in seconds) between LALBarycenter() and XLALBarycenter()  = %g s, exceeding tolerance of %g s\n", maxEmitDiff, tolerance );

  XLALPrintInfo ( "Max error (in seconds) between LALBarycenter() and XLALBarycenterOpt()  = %g s (tolerance = %g s)\n", maxEmitDiffOpt, tolerance );
  XLAL_CHECK ( maxEmitDiffOpt < tolerance, XLAL_EFAILED,
               "Max error (in seconds) between LALBarycenter() and XLALBarycenterOpt()  = %g s, exceeding tolerance of %g s\n",
               maxEmitDiffOpt, tolerance );
  printf ( "%g	%g %d %d %g	%g %g %g	%g %g %g\n",
           maxEmitDiffOpt,
           maxDiffOpt.deltaT, maxDiffOpt.te.gpsSeconds, maxDiffOpt.te.gpsNanoSeconds, maxDiffOpt.tDot,
           maxDiffOpt.rDetector[0], maxDiffOpt.rDetector[1], maxDiffOpt.rDetector[2],
           maxDiffOpt.vDetector[0], maxDiffOpt.vDetector[1], maxDiffOpt.vDetector[2]
           );

  /* ----- output runtimes ---------- */
  XLALPrintError ("Runtimes per function-call, averaged over %g calls\n", 1.0 * NRepeat * counter );
  XLALPrintError ("LALBarycenter() 	%g s\n", tau_lal / counter );
  XLALPrintError ("XLALBarycenter()	%g s (= %.1f %%)\n", tau_xlal / counter, - 100 * (tau_lal - tau_xlal ) / tau_lal );
  XLALPrintError ("XLALBarycenterOpt()	%g s (= %.1f %%)\n", tau_opt / counter,  - 100 * (tau_lal - tau_opt ) / tau_lal );

  /* ===== test XLALRestrictEphemerisData() ===== */
  XLALPrintInfo("\n\nTesting XLALRestrictEphemerisData() ... ");
  {
    XLAL_CHECK( edat.nentriesS >= 100, XLAL_EFAILED );
    const INT4 orig_nentriesS = edat.nentriesS;
    for (INT4 i = 1; i <= 4; ++i) {
      REAL8 start, end;
      LIGOTimeGPS startGPS, endGPS;
      INT4 diff_nentriesS;

      start = edat.ephemS[2*i].gps;
      end = edat.ephemS[edat.nentriesS - 1 - 3*i].gps;
      XLAL_CHECK( XLALGPSSetREAL8(&startGPS, start) != NULL, XLAL_EFUNC );
      XLAL_CHECK( XLALGPSSetREAL8(&endGPS, end) != NULL, XLAL_EFUNC );
      XLAL_CHECK( XLALRestrictEphemerisData(&edat, &startGPS, &endGPS) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK( edat.ephemS[0].gps == start, XLAL_EFAILED, "\nTest S%dA FAILED: %0.9f != start %0.9f\n", i, edat.ephemS[0].gps, start );
      XLAL_CHECK( edat.ephemS[edat.nentriesS - 1].gps == end, XLAL_EFAILED, "\nTest S%dA FAILED: end %0.9f != %0.9f\n", i, edat.ephemS[edat.nentriesS - 1].gps, end );
      diff_nentriesS = ((i*i + i) * 5) / 2 + 2*(i-1);
      XLAL_CHECK( orig_nentriesS - edat.nentriesS == diff_nentriesS, XLAL_EFAILED, "\nTest S%dA FAILED: nentries %d != %d\n", i, orig_nentriesS - edat.nentriesS, diff_nentriesS );

      XLAL_CHECK( XLALGPSSetREAL8(&startGPS, start + 0.5*edat.dtStable) != NULL, XLAL_EFUNC );
      XLAL_CHECK( XLALGPSSetREAL8(&endGPS, end - 0.5*edat.dtStable) != NULL, XLAL_EFUNC );
      start = edat.ephemS[0].gps;
      end = edat.ephemS[edat.nentriesS - 1].gps;
      XLAL_CHECK( XLALRestrictEphemerisData(&edat, &startGPS, &endGPS) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK( edat.ephemS[0].gps == start, XLAL_EFAILED, "\nTest S%dB FAILED: start %0.9f != %0.9f\n", i, edat.ephemS[0].gps, start );
      XLAL_CHECK( edat.ephemS[edat.nentriesS - 1].gps == end, XLAL_EFAILED, "\nTest S%dB FAILED: end %0.9f != %0.9f\n", i, edat.ephemS[edat.nentriesS - 1].gps, end );
      diff_nentriesS = ((i*i + i) * 5) / 2 + 2*(i-1);
      XLAL_CHECK( orig_nentriesS - edat.nentriesS == diff_nentriesS, XLAL_EFAILED, "\nTest S%dB FAILED: nentries %d != %d\n", i, orig_nentriesS - edat.nentriesS, diff_nentriesS );

      XLAL_CHECK( XLALGPSSetREAL8(&startGPS, start + 1.5*edat.dtStable) != NULL, XLAL_EFUNC );
      XLAL_CHECK( XLALGPSSetREAL8(&endGPS, end - 1.5*edat.dtStable) != NULL, XLAL_EFUNC );
      start = edat.ephemS[1].gps;
      end = edat.ephemS[edat.nentriesS - 2].gps;
      XLAL_CHECK( XLALRestrictEphemerisData(&edat, &startGPS, &endGPS) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK( edat.ephemS[0].gps == start, XLAL_EFAILED, "\nTest S%dC FAILED: start %0.9f != %0.9f\n", i, edat.ephemS[0].gps, start );
      XLAL_CHECK( edat.ephemS[edat.nentriesS - 1].gps == end, XLAL_EFAILED, "\nTest S%dC FAILED: end %0.9f != %0.9f\n", i, edat.ephemS[edat.nentriesS - 1].gps, end );
      diff_nentriesS = ((i*i + i) * 5) / 2 + 2*i;
      XLAL_CHECK( orig_nentriesS - edat.nentriesS == diff_nentriesS, XLAL_EFAILED, "\nTest S%dC FAILED: nentries %d != %d\n", i, orig_nentriesS - edat.nentriesS, diff_nentriesS );
    }

    XLAL_CHECK( edat.nentriesE >= 100, XLAL_EFAILED );
    const INT4 orig_nentriesE = edat.nentriesE;
    for (INT4 i = 1; i <= 4; ++i) {
      REAL8 start, end;
      LIGOTimeGPS startGPS, endGPS;
      INT4 diff_nentriesE;

      start = edat.ephemE[2*i].gps;
      end = edat.ephemE[edat.nentriesE - 1 - 3*i].gps;
      XLAL_CHECK( XLALGPSSetREAL8(&startGPS, start) != NULL, XLAL_EFUNC );
      XLAL_CHECK( XLALGPSSetREAL8(&endGPS, end) != NULL, XLAL_EFUNC );
      XLAL_CHECK( XLALRestrictEphemerisData(&edat, &startGPS, &endGPS) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK( edat.ephemE[0].gps == start, XLAL_EFAILED, "\nTest E%dA FAILED: %0.9f != start %0.9f\n", i, edat.ephemE[0].gps, start );
      XLAL_CHECK( edat.ephemE[edat.nentriesE - 1].gps == end, XLAL_EFAILED, "\nTest E%dA FAILED: end %0.9f != %0.9f\n", i, edat.ephemE[edat.nentriesE - 1].gps, end );
      diff_nentriesE = ((i*i + i) * 5) / 2 + 2*(i-1);
      XLAL_CHECK( orig_nentriesE - edat.nentriesE == diff_nentriesE, XLAL_EFAILED, "\nTest E%dA FAILED: nentries %d != %d\n", i, orig_nentriesE - edat.nentriesE, diff_nentriesE );

      XLAL_CHECK( XLALGPSSetREAL8(&startGPS, start + 0.5*edat.dtEtable) != NULL, XLAL_EFUNC );
      XLAL_CHECK( XLALGPSSetREAL8(&endGPS, end - 0.5*edat.dtEtable) != NULL, XLAL_EFUNC );
      start = edat.ephemE[0].gps;
      end = edat.ephemE[edat.nentriesE - 1].gps;
      XLAL_CHECK( XLALRestrictEphemerisData(&edat, &startGPS, &endGPS) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK( edat.ephemE[0].gps == start, XLAL_EFAILED, "\nTest E%dB FAILED: start %0.9f != %0.9f\n", i, edat.ephemE[0].gps, start );
      XLAL_CHECK( edat.ephemE[edat.nentriesE - 1].gps == end, XLAL_EFAILED, "\nTest E%dB FAILED: end %0.9f != %0.9f\n", i, edat.ephemE[edat.nentriesE - 1].gps, end );
      diff_nentriesE = ((i*i + i) * 5) / 2 + 2*(i-1);
      XLAL_CHECK( orig_nentriesE - edat.nentriesE == diff_nentriesE, XLAL_EFAILED, "\nTest E%dB FAILED: nentries %d != %d\n", i, orig_nentriesE - edat.nentriesE, diff_nentriesE );

      XLAL_CHECK( XLALGPSSetREAL8(&startGPS, start + 1.5*edat.dtEtable) != NULL, XLAL_EFUNC );
      XLAL_CHECK( XLALGPSSetREAL8(&endGPS, end - 1.5*edat.dtEtable) != NULL, XLAL_EFUNC );
      start = edat.ephemE[1].gps;
      end = edat.ephemE[edat.nentriesE - 2].gps;
      XLAL_CHECK( XLALRestrictEphemerisData(&edat, &startGPS, &endGPS) == XLAL_SUCCESS, XLAL_EFUNC );
      XLAL_CHECK( edat.ephemE[0].gps == start, XLAL_EFAILED, "\nTest E%dC FAILED: start %0.9f != %0.9f\n", i, edat.ephemE[0].gps, start );
      XLAL_CHECK( edat.ephemE[edat.nentriesE - 1].gps == end, XLAL_EFAILED, "\nTest E%dC FAILED: end %0.9f != %0.9f\n", i, edat.ephemE[edat.nentriesE - 1].gps, end );
      diff_nentriesE = ((i*i + i) * 5) / 2 + 2*i;
      XLAL_CHECK( orig_nentriesE - edat.nentriesE == diff_nentriesE, XLAL_EFAILED, "\nTest E%dC FAILED: nentries %d != %d\n", i, orig_nentriesE - edat.nentriesE, diff_nentriesE );
    }
  }
  XLALPrintInfo("PASSED\n\n");

  LALFree(edat.ephemE);
  LALFree(edat.ephemS);

  LALCheckMemoryLeaks();

  XLALPrintError ("==> OK. All tests successful!\n\n");

  return 0;

} /* main() */
Example #2
0
int get_barycenter (double gps1, Detectors site, EphemerisData *edat,	\
		    double *DetSSB, double *rDet, double dt, int len) {
  int i;
  double gps;
  BarycenterInput baryinput;
  EarthState earth;
  EmissionTime emit;

  switch (site) {
  case H1:
  case H2:
  case LHO:
    baryinput.site.location[0] = -2161414.92636;
    baryinput.site.location[1] = -3834695.17889;
    baryinput.site.location[2] = 4600350.22664;
    break;
  case L1:
  case LLO:
    baryinput.site.location[0] = -74276.04472380;
    baryinput.site.location[1] = -5496283.71971000;
    baryinput.site.location[2] = 3224257.01744000;
    break;
  case V1:
  case VIRGO:
    baryinput.site.location[0] = 4546374.09900000;
    baryinput.site.location[1] = 842989.69762600;
    baryinput.site.location[2] = 4378576.96241000;
    break;
  case none:
  default:
    baryinput.site.location[0] = 0.;
    baryinput.site.location[1] = 0.;
    baryinput.site.location[2] = 0.;
    fprintf (stderr, "No coordinates found for detector site, ");
    fprintf (stderr, "using defaults\n");
  }

  /* set positions in light seconds */
  for (i=0; i<3; i++)
    baryinput.site.location[i] /= C_SI;

  /* main loop */
  for (i=0; i<len; i++) {
    gps = gps1+i*dt;
    /* split time into seconds and nanoseconds */
    baryinput.tgps.gpsSeconds = floor(gps);
    baryinput.tgps.gpsNanoSeconds =		\
      (gps-baryinput.tgps.gpsSeconds)*1.e9;
    /* perform Earth barycentring */
    XLALBarycenterEarth (&earth, &baryinput.tgps, edat);

    /* set source information & perform barycentring */
    /* x component */
    baryinput.alpha = 0.;
    baryinput.delta = 0.;
    baryinput.dInv = 0.;
    XLALBarycenter (&emit, &baryinput, &earth);
    DetSSB[3*i] = emit.deltaT/dt;
    rDet[3*i] = emit.erot/dt;

    /* y component */
    baryinput.alpha = M_PI_2;
    baryinput.delta = 0.;
    baryinput.dInv = 0.;
    XLALBarycenter (&emit, &baryinput, &earth);
    DetSSB[3*i+1] = emit.deltaT/dt;
    rDet[3*i+1] = emit.erot/dt;

    /* z component */
    baryinput.alpha = 0.;
    baryinput.delta = M_PI_2;
    baryinput.dInv = 0.;
    XLALBarycenter (&emit, &baryinput, &earth);
    DetSSB[3*i+2] = emit.deltaT/dt;
    rDet[3*i+2] = emit.erot/dt;
  }
  return 0;
}
Example #3
0
/**
 * Get the 'detector state' (ie detector-tensor, position, velocity, etc) for the given
 * vector of timestamps, shifted by a common time-shift \a tOffset.
 *
 * This function just calls XLALBarycenterEarth() and XLALBarycenter() for the
 * given vector of timestamps (shifted by tOffset) and returns the positions,
 * velocities and LMSTs of the detector, stored in a DetectorStateSeries.
 * There is also an entry containing the EarthState at each timestamp, which
 * can be used as input for subsequent calls to XLALBarycenter().
 *
 * \a tOffset allows one to easily use the midpoints of SFT-timestamps, for example.
 *
 */
DetectorStateSeries *
XLALGetDetectorStates ( const LIGOTimeGPSVector *timestamps,	/**< array of GPS timestamps t_i */
                        const LALDetector *detector,		/**< detector info */
                        const EphemerisData *edat,		/**< ephemeris file data */
                        REAL8 tOffset				/**< compute detector states at timestamps SHIFTED by tOffset */
                        )
{
  /* check input consistency */
  if ( !timestamps || !detector || !edat ) {
    XLALPrintError ("%s: invalid NULL input, timestamps=%p, detector=%p, edat=%p\n", __func__, timestamps, detector, edat );
    XLAL_ERROR_NULL ( XLAL_EINVAL );
  }

  /* prepare return vector */
  UINT4 numSteps = timestamps->length;
  DetectorStateSeries *ret = NULL;
  if ( ( ret = XLALCreateDetectorStateSeries ( numSteps )) == NULL ) {
    XLALPrintError ("%s: XLALCreateDetectorStateSeries(%d) failed.\n", __func__, numSteps );
    XLAL_ERROR_NULL ( XLAL_EFUNC );
  }

  /* enter detector-info into the head of the state-vector */
  ret->detector = (*detector);

  /* set 'time-span' associated with each timestamp */
  ret->deltaT = timestamps->deltaT;

  /* set SSB coordinate system used: EQUATORIAL for Earth-based, ECLIPTIC for LISA */
  if ( detector->frDetector.prefix[0] == 'Z' )	/* LISA */
    ret->system = COORDINATESYSTEM_ECLIPTIC;
  else	/* Earth-based */
    ret->system = COORDINATESYSTEM_EQUATORIAL;

  /* now fill all the vector-entries corresponding to different timestamps */
  UINT4 i;
  for ( i=0; i < numSteps; i++ )
    {
      BarycenterInput baryinput;
      EmissionTime emit;
      DetectorState *state = &(ret->data[i]);
      EarthState *earth = &(state->earthState);
      LIGOTimeGPS tgps;

      /* shift timestamp by tOffset */
      tgps = timestamps->data[i];
      XLALGPSAdd(&tgps, tOffset);

      /*----- first get earth-state */
      if ( XLALBarycenterEarth ( earth, &tgps, edat ) != XLAL_SUCCESS ) {
        XLALDestroyDetectorStateSeries ( ret );
        XLALPrintError("%s: XLALBarycenterEarth() failed with xlalErrno=%d\n", __func__, xlalErrno );
        XLAL_ERROR_NULL ( XLAL_EFAILED );
      }

      /*----- then get detector-specific info */
      baryinput.tgps = tgps;
      baryinput.site = (*detector);
      baryinput.site.location[0] /= LAL_C_SI;
      baryinput.site.location[1] /= LAL_C_SI;
      baryinput.site.location[2] /= LAL_C_SI;
      baryinput.alpha = baryinput.delta = 0;	/* irrelevant */
      baryinput.dInv = 0;

      if ( XLALBarycenter ( &emit, &baryinput, earth) != XLAL_SUCCESS ) {
	XLALDestroyDetectorStateSeries( ret );
        XLALPrintError("%s: XLALBarycenterEarth() failed with xlalErrno=%d\n", __func__, xlalErrno );
        XLAL_ERROR_NULL ( XLAL_EFAILED );
      }

      /*----- extract the output-data from this */
      UINT4 j;
      for (j=0; j < 3; j++)	/* copy detector's position and velocity */
	{
	  state->rDetector[j] = emit.rDetector[j];
	  state->vDetector[j] = emit.vDetector[j];
	} /* for j < 3 */

      /* local mean sidereal time = GMST + longitude */
      state->LMST = earth->gmstRad + detector->frDetector.vertexLongitudeRadians;
      state->LMST = fmod (state->LMST, LAL_TWOPI );	/* normalize */

      /* insert timestamp */
      state->tGPS = tgps;

      /* compute the detector-tensor at this time-stamp in SSB-fixed Cartesian coordinates
       * [EQUATORIAL for Earth-based, ECLIPTIC for LISA]
       */
      if ( XLALFillDetectorTensor ( state, detector ) != 0 ) {
	XLALDestroyDetectorStateSeries(ret);
	XLALPrintError ( "%s: XLALFillDetectorTensor() failed ... errno = %d\n\n", __func__, xlalErrno );
	XLAL_ERROR_NULL ( XLAL_EFUNC );
      }

    } /* for i < numSteps */

  /* return result */
  return ret;

} /* XLALGetDetectorStates() */