/** * Function to compute the LWL detector-tensor for the given \a detector in * SSB-fixed cartesian coordinates at time tgps. * The coordinates used are: EQUATORIAL for Earth-based detectors, but ECLIPTIC for LISA. * RETURN: 0 = OK, -1 = ERROR */ int XLALFillDetectorTensor (DetectorState *detState, /**< [out,in]: detector state: fill in detector-tensor */ const LALDetector *detector /**< [in]: which detector */ ) { const CHAR *prefix; if ( !detState || !detector ) { xlalErrno = XLAL_EINVAL; return -1; } prefix = detector->frDetector.prefix; /* we need to distinguish two cases: space-borne (i.e. LISA) and Earth-based detectors */ if ( prefix[0] == 'Z' ) /* LISA */ { if ( XLALprecomputeLISAarms ( detState ) != 0 ) { XLALPrintError ("\nXLALprecomputeLISAarms() failed !\n\n"); xlalErrno = XLAL_EINVAL; return -1; } if ( XLALgetLISADetectorTensorLWL ( &(detState->detT), detState->detArms, prefix[1] ) != 0 ) { XLALPrintError ("\nXLALgetLISADetectorTensorLWL() failed !\n\n"); xlalErrno = XLAL_EINVAL; return -1; } } /* if LISA */ else { REAL4 sinG, cosG, sinGcosG, sinGsinG, cosGcosG; SymmTensor3 *detT = &(detState->detT); XLAL_CHECK( XLALSinCosLUT ( &sinG, &cosG, detState->earthState.gmstRad ) == XLAL_SUCCESS, XLAL_EFUNC ); sinGsinG = sinG * sinG; sinGcosG = sinG * cosG; cosGcosG = cosG * cosG; /* printf("GMST = %fdeg; cosG = %f, sinG= %f\n", LAL_180_PI * atan2(sinG,cosG), cosG, sinG); */ detT->d11 = detector->response[0][0] * cosGcosG - 2 * detector->response[0][1] * sinGcosG + detector->response[1][1] * sinGsinG; detT->d22 = detector->response[0][0] * sinGsinG + 2 * detector->response[0][1] * sinGcosG + detector->response[1][1] * cosGcosG; detT->d12 = (detector->response[0][0] - detector->response[1][1]) * sinGcosG + detector->response[0][1] * (cosGcosG - sinGsinG); detT->d13 = detector->response[0][2] * cosG - detector->response[1][2] * sinG; detT->d23 = detector->response[0][2] * sinG + detector->response[1][2] * cosG; detT->d33 = detector->response[2][2]; /* printf("d = (%f %f %f\n",detT->d11,detT->d12,detT->d13); printf(" %f %f %f\n",detT->d12,detT->d22,detT->d23); printf(" %f %f %f)\n",detT->d13,detT->d23,detT->d33); printf("d*= (%f %f %f\n",detector->response[0][0], detector->response[0][1],detector->response[0][2]); printf(" %f %f %f\n",detector->response[1][0], detector->response[1][1],detector->response[1][2]); printf(" %f %f %f)\n",detector->response[2][0], detector->response[2][1],detector->response[2][2]); */ } /* if Earth-based */ return 0; } /* XLALFillDetectorTensor() */
/** Interpolate a given regularly-spaced COMPLEX8 timeseries 'ts_in = x_in(j * dt)' onto new samples * 'y_out(t_out)' using Shannon sinc interpolation truncated to (2*Dterms+1) terms, namely * * \f{equation}{ * x(t) = \sum_{j = j^* - \Delta j}^{j^* + \Delta j} x_j \,\, \frac{\sin(\pi\delta_j)}{\pi\delta_j}\,,\quad\text{with}\quad * \delta_j \equiv \frac{t - t_j}{\Delta t}\,, * \f} * and where \f$j^* \equiv \mathrm{round}(t / \Delta t)\f$. * * In order to implement this more efficiently, we observe that \f$\sin(\pi\delta_j) = (-1)^{(j-j0)}\sin(\pi\delta_{j0})\f$ for integer \f$j\f$, * and therefore * * \f{equation}{ * x(t) = \frac{\sin(\pi\,\delta_{j0})}{\pi} \, \sum_{j = j^* - \Delta j}^{j^* + \Delta j} (-1)^{(j-j0)}\frac{x_j}{\delta_j}\,, * \f} * * NOTE: Using Dterms=0 corresponds to closest-bin interpolation * * NOTE2: samples *outside* the original timespan are returned as 0 */ int XLALSincInterpolateCOMPLEX8TimeSeries ( COMPLEX8Vector *y_out, ///< [out] output series of interpolated y-values [must be same size as t_out] const REAL8Vector *t_out, ///< [in] output time-steps to interpolate input to const COMPLEX8TimeSeries *ts_in,///< [in] regularly-spaced input timeseries UINT4 Dterms ///< [in] truncate sinc kernel sum to +-Dterms around max ) { XLAL_CHECK ( y_out != NULL, XLAL_EINVAL ); XLAL_CHECK ( t_out != NULL, XLAL_EINVAL ); XLAL_CHECK ( ts_in != NULL, XLAL_EINVAL ); XLAL_CHECK ( y_out->length == t_out->length, XLAL_EINVAL ); UINT4 numSamplesOut = t_out->length; UINT4 numSamplesIn = ts_in->data->length; REAL8 dt = ts_in->deltaT; REAL8 tmin = XLALGPSGetREAL8 ( &(ts_in->epoch) ); // time of first bin in input timeseries const REAL8 oodt = 1.0 / dt; for ( UINT4 l = 0; l < numSamplesOut; l ++ ) { REAL8 t = t_out->data[l] - tmin; // measure time since start of input timeseries // samples outside of input timeseries are returned as 0 if ( (t < 0) || (t > (numSamplesIn-1)*dt) ) // avoid any extrapolations! { y_out->data[l] = 0; continue; } REAL8 t_by_dt = t * oodt; INT8 jstar = lround ( t_by_dt ); // bin closest to 't', guaranteed to be in [0, numSamples-1] if ( fabs ( t_by_dt - jstar ) < LD_SMALL4 ) // avoid numerical problems near peak { y_out->data[l] = ts_in->data->data[jstar]; // known analytic solution for exact bin continue; } UINT8 jStart = MYMAX ( jstar - Dterms, 0 ); UINT8 jEnd = MYMIN ( jstar + Dterms, numSamplesIn - 1 ); REAL4 delta_jStart = (t_by_dt - jStart); REAL4 sin0, cos0; XLALSinCosLUT ( &sin0, &cos0, LAL_PI * delta_jStart ); REAL4 sin0oopi = sin0 * OOPI; COMPLEX8 y_l = 0; REAL8 delta_j = delta_jStart; for ( UINT8 j = jStart; j <= jEnd; j ++ ) { COMPLEX8 Cj = sin0oopi / delta_j; y_l += Cj * ts_in->data->data[j]; sin0oopi = -sin0oopi; // sin-term flips sign every step delta_j --; } // for j in [j* - Dterms, ... ,j* + Dterms] y_out->data[l] = y_l; } // for l < numSamplesOut return XLAL_SUCCESS; } // XLALSincInterpolateCOMPLEX8TimeSeries()
/** * Compute the 'amplitude coefficients' \f$a(t)\sin\zeta\f$, * \f$b(t)\sin\zeta\f$ as defined in \cite JKS98 for a series of * timestamps. * * The input consists of the DetectorState-timeseries, which contains * the detector-info and the LMST's corresponding to the different times. * * \note This is an equivalent implementation to LALNewGetAMCoeffs(), * only using the XLAL interface instead. * This implementation is based on the geometrical definition of * \f$a\sin\zeta\f$ and \f$b\sin\zeta\f$ as detector response * coefficients in a preferred polarization basis. (It is thereby * more general than the JKS expressions and could be used e.g., with * the response tensor of a bar detector with no further modification * needed.) * * \note The fields AMCoeffs->{A, B, C, D} are not computed by this function, * as they require correct SFT noise-weights. These fields would be computed, for * example by XLALWeightMultiAMCoeffs(). * */ AMCoeffs * XLALComputeAMCoeffs ( const DetectorStateSeries *DetectorStates, /**< timeseries of detector states */ SkyPosition skypos /**< {alpha,delta} of the source */ ) { /* ---------- check input consistency ---------- */ if ( !DetectorStates ) { XLALPrintError ("%s: invalid NULL input 'DetectorStates'\n", __func__ ); XLAL_ERROR_NULL ( XLAL_EINVAL ); } /* currently requires sky-pos to be in equatorial coordinates (FIXME) */ if ( skypos.system != COORDINATESYSTEM_EQUATORIAL ) { XLALPrintError ("%s: only equatorial coordinates currently supported in 'skypos'\n", __func__ ); XLAL_ERROR_NULL ( XLAL_EINVAL ); } /*---------- We write components of xi and eta vectors in SSB-fixed coords */ REAL4 alpha = skypos.longitude; REAL4 delta = skypos.latitude; REAL4 sin1delta, cos1delta; REAL4 sin1alpha, cos1alpha; XLAL_CHECK_NULL( XLALSinCosLUT (&sin1delta, &cos1delta, delta ) == XLAL_SUCCESS, XLAL_EFUNC ); XLAL_CHECK_NULL( XLALSinCosLUT (&sin1alpha, &cos1alpha, alpha ) == XLAL_SUCCESS, XLAL_EFUNC ); REAL4 xi1 = - sin1alpha; REAL4 xi2 = cos1alpha; REAL4 eta1 = sin1delta * cos1alpha; REAL4 eta2 = sin1delta * sin1alpha; REAL4 eta3 = - cos1delta; /* prepare output vector */ UINT4 numSteps = DetectorStates->length; AMCoeffs *coeffs; if ( ( coeffs = XLALCreateAMCoeffs ( numSteps ) ) == NULL ) { XLALPrintError ("%s: XLALCreateAMCoeffs(%d) failed\n", __func__, numSteps ); XLAL_ERROR_NULL ( XLAL_EFUNC ); } /*---------- Compute the a(t_i) and b(t_i) ---------- */ UINT4 i; for ( i=0; i < numSteps; i++ ) { REAL4 ai, bi; SymmTensor3 *d = &(DetectorStates->data[i].detT); ai = d->d11 * ( xi1 * xi1 - eta1 * eta1 ) + 2 * d->d12 * ( xi1*xi2 - eta1*eta2 ) - 2 * d->d13 * eta1 * eta3 + d->d22 * ( xi2*xi2 - eta2*eta2 ) - 2 * d->d23 * eta2 * eta3 - d->d33 * eta3*eta3; bi = d->d11 * 2 * xi1 * eta1 + 2 * d->d12 * ( xi1 * eta2 + xi2 * eta1 ) + 2 * d->d13 * xi1 * eta3 + d->d22 * 2 * xi2 * eta2 + 2 * d->d23 * xi2 * eta3; coeffs->a->data[i] = ai; coeffs->b->data[i] = bi; } /* for i < numSteps */ /* return the result */ return coeffs; } /* XLALComputeAMCoeffs() */
/** * Compute the 'amplitude coefficients' \f$a(t), b(t)\f$ as defined in * \cite JKS98 for a series of timestamps. * * The input consists of the DetectorState-timeseries, which contains * the detector-info and the LMST's corresponding to the different times. * * In order to allow re-using the output-structure AMCoeffs for subsequent * calls, we require the REAL4Vectors a and b to be allocated already and * to have the same length as the DetectoStates-timeseries. * * \note This is an alternative implementation to LALComputeAM() with * the aim to be both simpler and faster. * The difference being that we don't implicitly re-derive the final expression * here but simply try to implement the final expressions (12), (13) in \cite JKS98 * in the most economical way possible. */ void LALGetAMCoeffs(LALStatus *status, /**< [in/out] LAL status structure pointer */ AMCoeffs *coeffs, /**< [out] amplitude-coeffs {a(t_i), b(t_i)} */ const DetectorStateSeries *DetectorStates, /**< timeseries of detector states */ SkyPosition skypos /**< {alpha,delta} of the source */ ) { REAL4 ah1, ah2, ah3, ah4, ah5; REAL4 a1, a2, a3, a4, a5; REAL4 bh1, bh2, bh3, bh4; REAL4 b1, b2, b3, b4; REAL4 delta, alpha; REAL4 sin1delta, cos1delta, sin2delta, cos2delta; REAL4 gam, lambda; REAL4 norm; UINT4 i, numSteps; INITSTATUS(status); /*---------- check input ---------- */ ASSERT ( DetectorStates, status, LALCOMPUTEAMH_ENULL, LALCOMPUTEAMH_MSGENULL); numSteps = DetectorStates->length; /* require the coeffients-vectors to be allocated and consistent with timestamps */ ASSERT ( coeffs, status, LALCOMPUTEAMH_ENULL, LALCOMPUTEAMH_MSGENULL); ASSERT ( coeffs->a && coeffs->b, status, LALCOMPUTEAMH_ENULL, LALCOMPUTEAMH_MSGENULL); ASSERT ( (coeffs->a->length == numSteps) && (coeffs->b->length == numSteps), status, LALCOMPUTEAMH_EINPUT, LALCOMPUTEAMH_MSGEINPUT); /* require sky-pos to be in equatorial coordinates */ ASSERT ( skypos.system == COORDINATESYSTEM_EQUATORIAL, status, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); /*---------- detector paramters: lambda, L, gamma */ { /* FIXME: put into DetectorStateSeries */ /* orientation of detector arms */ REAL8 xAzi = DetectorStates->detector.frDetector.xArmAzimuthRadians; REAL8 yAzi = DetectorStates->detector.frDetector.yArmAzimuthRadians; /* get detector orientation gamma */ gam = LAL_PI_2 - 0.5 * (xAzi + yAzi); /* get detector position latitude (lambda) */ lambda = DetectorStates->detector.frDetector.vertexLatitudeRadians; /* printf ("IFO = %s: sin(zeta) = %f\n", DetectorStates->detector.frDetector.name, sin( xAzi - yAzi ) ); */ } /*---------- coefficient ahN, bhN dependent ONLY on detector-position ---------- */ /* FIXME: put these coefficients into DetectorStateSeries */ { REAL4 sin2gamma, cos2gamma; REAL4 sin1lambda, cos1lambda; REAL4 sin2lambda, cos2lambda; if( XLALSinCosLUT (&sin2gamma, &cos2gamma, 2.0f * gam ) != XLAL_SUCCESS ) ABORT( status->statusPtr, LAL_EXLAL, "XLALSinCosLUT (&sin2gamma, &cos2gamma, 2.0f * gam ) failed" ); if( XLALSinCosLUT (&sin1lambda, &cos1lambda, lambda ) != XLAL_SUCCESS ) ABORT( status->statusPtr, LAL_EXLAL, "XLALSinCosLUT (&sin1lambda, &cos1lambda, lambda ) failed" ); sin2lambda = 2.0f * sin1lambda * cos1lambda; cos2lambda = cos1lambda * cos1lambda - sin1lambda * sin1lambda; /* coefficients for a(t) */ ah1 = 0.0625f * sin2gamma * (3.0f - cos2lambda); /* 1/16 = 0.0625 */ ah2 = - 0.25f * cos2gamma * sin1lambda; ah3 = 0.25f * sin2gamma * sin2lambda; ah4 = -0.5f * cos2gamma * cos1lambda; ah5 = 0.75f * sin2gamma * cos1lambda * cos1lambda; /* coefficients for b(t) */ bh1 = cos2gamma * sin1lambda; bh2 = 0.25f * sin2gamma * (3.0f - cos2lambda); bh3 = cos2gamma * cos1lambda; bh4 = 0.5f * sin2gamma * sin2lambda; } /*---------- coefficients aN, bN dependent ONLY on {ahN, bhN} and source-latitude delta */ alpha = skypos.longitude; delta = skypos.latitude; if( XLALSinCosLUT (&sin1delta, &cos1delta, delta ) != XLAL_SUCCESS ) ABORT( status->statusPtr, LAL_EXLAL, "XLALSinCosLUT (&sin1delta, &cos1delta, delta ) failed" ); sin2delta = 2.0f * sin1delta * cos1delta; cos2delta = cos1delta * cos1delta - sin1delta * sin1delta; /* coefficients for a(t) */ a1 = ah1 * ( 3.0f - cos2delta ); a2 = ah2 * ( 3.0f - cos2delta ); a3 = ah3 * sin2delta; a4 = ah4 * sin2delta; a5 = ah5 * cos1delta * cos1delta; /* coefficients for b(t) */ b1 = bh1 * sin1delta; b2 = bh2 * sin1delta; b3 = bh3 * cos1delta; b4 = bh4 * cos1delta; /*---------- Compute the a(t_i) and b(t_i) ---------- */ coeffs->A = 0; coeffs->B = 0; coeffs->C = 0; coeffs->D = 0; for ( i=0; i < numSteps; i++ ) { REAL4 ah; REAL4 cos1ah, sin1ah, cos2ah, sin2ah; REAL4 ai, bi; ah = alpha - DetectorStates->data[i].LMST; if( XLALSinCosLUT ( &sin1ah, &cos1ah, ah ) != XLAL_SUCCESS ) ABORT( status->statusPtr, LAL_EXLAL, "XLALSinCosLUT ( &sin1ah, &cos1ah, ah ) failed" ); sin2ah = 2.0f * sin1ah * cos1ah; cos2ah = cos1ah * cos1ah - sin1ah * sin1ah; ai = a1 * cos2ah + a2 * sin2ah + a3 * cos1ah + a4 * sin1ah + a5; bi = b1 * cos2ah + b2 * sin2ah + b3 * cos1ah + b4 * sin1ah; coeffs->a->data[i] = ai; coeffs->b->data[i] = bi; /* sum A, B, C on the fly */ coeffs->A += ai * ai; coeffs->B += bi * bi; coeffs->C += ai * bi; } /* for i < numSteps */ /* finish calculation of A,B,C, D */ norm = 2.0f / numSteps; coeffs->A *= norm; coeffs->B *= norm; coeffs->C *= norm; coeffs->D = coeffs->A * coeffs->B - coeffs->C * coeffs->C; RETURN(status); } /* LALGetAMCoeffs() */
/** * Compute the 'amplitude coefficients' \f$a(t)\sin\zeta\f$, * \f$b(t)\sin\zeta\f$ as defined in \cite JKS98 for a series of * timestamps. * * The input consists of the DetectorState-timeseries, which contains * the detector-info and the LMST's corresponding to the different times. * * In order to allow re-using the output-structure AMCoeffs for subsequent * calls, we require the REAL4Vectors a and b to be allocated already and * to have the same length as the DetectoStates-timeseries. * * \note This is an alternative implementation to both LALComputeAM() * and LALGetAMCoeffs(), which uses the geometrical definition of * \f$a\sin\zeta\f$ and \f$b\sin\zeta\f$ as detector response * coefficients in a preferred polarization basis. (It is thereby * more general than the JKS expressions and could be used e.g., with * the response tensor of a bar detector with no further modification * needed.) */ void LALNewGetAMCoeffs(LALStatus *status, /**< [in/out] LAL status structure pointer */ AMCoeffs *coeffs, /**< [out] amplitude-coeffs {a(t_i), b(t_i)} */ const DetectorStateSeries *DetectorStates,/**< timeseries of detector states */ SkyPosition skypos /**< {alpha,delta} of the source */ ) { REAL4 delta, alpha; REAL4 sin1delta, cos1delta; REAL4 sin1alpha, cos1alpha; REAL4 xi1, xi2; REAL4 eta1, eta2, eta3; REAL4 norm; UINT4 i, numSteps; INITSTATUS(status); /*---------- check input ---------- */ ASSERT ( DetectorStates, status, LALCOMPUTEAMH_ENULL, LALCOMPUTEAMH_MSGENULL); numSteps = DetectorStates->length; /* require the coeffients-vectors to be allocated and consistent with timestamps */ ASSERT ( coeffs, status, LALCOMPUTEAMH_ENULL, LALCOMPUTEAMH_MSGENULL); ASSERT ( coeffs->a && coeffs->b, status, LALCOMPUTEAMH_ENULL, LALCOMPUTEAMH_MSGENULL); ASSERT ( (coeffs->a->length == numSteps) && (coeffs->b->length == numSteps), status, LALCOMPUTEAMH_EINPUT, LALCOMPUTEAMH_MSGEINPUT); /* require sky-pos to be in equatorial coordinates */ ASSERT ( skypos.system == COORDINATESYSTEM_EQUATORIAL, status, SKYCOORDINATESH_ESYS, SKYCOORDINATESH_MSGESYS ); /*---------- We write components of xi and eta vectors in SSB-fixed coords */ alpha = skypos.longitude; delta = skypos.latitude; if( XLALSinCosLUT (&sin1delta, &cos1delta, delta ) != XLAL_SUCCESS ) ABORT( status->statusPtr, LAL_EXLAL, "XLALSinCosLUT (&sin1delta, &cos1delta, delta ) failed" ); if( XLALSinCosLUT (&sin1alpha, &cos1alpha, alpha ) != XLAL_SUCCESS ) ABORT( status->statusPtr, LAL_EXLAL, "XLALSinCosLUT (&sin1alpha, &cos1alpha, alpha ) failed" ); // see Eq.(17) in CFSv2 notes (version v3): // https://dcc.ligo.org/cgi-bin/private/DocDB/ShowDocument?docid=1665&version=3 xi1 = sin1alpha; xi2 = -cos1alpha; eta1 = -sin1delta * cos1alpha; eta2 = -sin1delta * sin1alpha; eta3 = cos1delta; /*---------- Compute the a(t_i) and b(t_i) ---------- */ coeffs->A = 0; coeffs->B = 0; coeffs->C = 0; coeffs->D = 0; for ( i=0; i < numSteps; i++ ) { REAL4 ai, bi; SymmTensor3 *d = &(DetectorStates->data[i].detT); ai = d->d11 * ( xi1 * xi1 - eta1 * eta1 ) + 2 * d->d12 * ( xi1*xi2 - eta1*eta2 ) - 2 * d->d13 * eta1 * eta3 + d->d22 * ( xi2*xi2 - eta2*eta2 ) - 2 * d->d23 * eta2 * eta3 - d->d33 * eta3*eta3; bi = d->d11 * 2 * xi1 * eta1 + 2 * d->d12 * ( xi1 * eta2 + xi2 * eta1 ) + 2 * d->d13 * xi1 * eta3 + d->d22 * 2 * xi2 * eta2 + 2 * d->d23 * xi2 * eta3; /* printf("xi = (%f,%f)\n",xi1,xi2); printf("eta = (%f,%f,%f)\n",eta1,eta2,eta3); printf("d = (%f %f %f\n",d->d11,d->d12,d->d13); printf(" %f %f %f\n",d->d12,d->d22,d->d23); printf(" %f %f %f)\n",d->d13,d->d23,d->d33); */ coeffs->a->data[i] = ai; coeffs->b->data[i] = bi; /* sum A, B, C on the fly */ coeffs->A += ai * ai; coeffs->B += bi * bi; coeffs->C += ai * bi; } /* for i < numSteps */ /* finish calculation of A,B,C, D */ norm = 2.0f / numSteps; coeffs->A *= norm; coeffs->B *= norm; coeffs->C *= norm; coeffs->D = coeffs->A * coeffs->B - coeffs->C * coeffs->C; RETURN(status); } /* LALNewGetAMCoeffs() */