LALInspiralComputePTFMetric.c

Go to the documentation of this file.
00001 /*
00002 *  Copyright (C) 2007 Yi Pan, Duncan Brown
00003 *
00004 *  This program is free software; you can redistribute it and/or modify
00005 *  it under the terms of the GNU General Public License as published by
00006 *  the Free Software Foundation; either version 2 of the License, or
00007 *  (at your option) any later version.
00008 *
00009 *  This program is distributed in the hope that it will be useful,
00010 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 *  GNU General Public License for more details.
00013 *
00014 *  You should have received a copy of the GNU General Public License
00015 *  along with with program; see the file COPYING. If not, write to the
00016 *  Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
00017 *  MA  02111-1307  USA
00018 */
00019 
00020 #if 0
00021 <lalVerbatim file="LALInspiralComputePTFMetricCV">
00022 Author: Yi Pan, Duncan Brown
00023 $Id: LALInspiralComputePTFMetric.c,v 1.8 2008/08/12 04:56:16 dfazi Exp $
00024 </lalVerbatim>
00025 
00026 <lalLaTeX>
00027 \subsection{Module \texttt{LALInspiralComputePTFMetric.c}}
00028 
00029 Module to compute the components of the metric which is used to describe
00030 distances on Physical Template Family signal manifold.
00031 
00032 \subsubsection*{Prototypes}
00033 \vspace{0.1in}
00034 \input{XLALInspiralComputePTFIntrinsicMetricCP}
00035 \idx{XLALInspiralComputePTFIntrinsicMetric()}
00036 \begin{itemize}
00037    \item \texttt{metric,} Output, the metric at the lattice point defined by \texttt{params}
00038    \item \texttt{psd,} Input, the power spectral density of the data
00039    \item \texttt{params,} Input, the parameters where metric must be computed
00040    in the computation of the metric.
00041 \end{itemize}
00042 
00043 \input{XLALInspiralComputePTFFullMetricCP}
00044 \idx{XLALInspiralComputePTFFullMetric()}
00045 \begin{itemize}
00046    \item \texttt{metric,} Output, the metric at the lattice point defined by \texttt{params}
00047    \item \texttt{psd,} Input, the power spectral density of the data
00048    \item \texttt{params,} Input, the parameters where metric must be computed
00049    in the computation of the metric.
00050 \end{itemize}
00051 
00052 \input{XLALInspiralComputePTFWaveformCP}
00053 \idx{XLALInspiralComputePTFWaveform()}
00054 \begin{itemize}
00055    \item \texttt{ptfwave,} Output, the waveform at the lattice point defined 
00056    by \texttt{params}
00057    \item \texttt{params,} Input, the parameters where metric must be computed
00058    in the computation of the metric.
00059 \end{itemize}
00060 
00061 \input{XLALInspiralComputePTFWDerivCP}
00062 \idx{XLALInspiralComputePTFWDeriv()}
00063 \begin{itemize}
00064    \item \texttt{Wderiv,} Output, the time derivative of waveform at the lattice 
00065    point defined by \texttt{params}
00066    \item \texttt{psd,}  Input, the power spectral density of the data
00067    \item \texttt{params,} Input, the parameters where metric must be computed
00068    in the computation of the metric
00069    \item \texttt{paramid,} Input, id of the parameter to take derivative on
00070    \item \texttt{initdelta,} Input, initial difference in parameters
00071    \item \texttt{tolerance,} Input, stop iteration when difference between two 
00072    bisections is smaller than tolerance.
00073 \end{itemize}
00074 
00075 \input{XLALInspiralComputePTFQDerivCP}
00076 \idx{XLALInspiralComputePTFQDeriv()}
00077 \begin{itemize}
00078    \item \texttt{Qderiv,} Output, the time derivative of Q at the lattice point 
00079    defined by \texttt{params}
00080    \item \texttt{params,} Input, the parameters where metric must be computed
00081    in the computation of the metric.
00082 \end{itemize}
00083 
00084 \subsubsection*{Description}
00085 We calculate the components of the metric using the procedure outlined 
00086 by Yi.
00087 
00088 \subsubsection*{Algorithm}
00089 
00090 \subsubsection*{Uses}
00091 
00092 \begin{verbatim}
00093 LALMalloc
00094 LALFree
00095 \end{verbatim}
00096 
00097 \subsubsection*{Notes}
00098  
00099 \vfill{\footnotesize\input{LALInspiralComputePTFMetricCV}}
00100 
00101 </lalLaTeX>
00102 #endif
00103 
00104 #include <stdlib.h>
00105 #include <lal/LALStdlib.h>
00106 #include <stdio.h>
00107 #include <lal/AVFactories.h>
00108 #include <lal/SeqFactories.h>
00109 #include <lal/LALInspiralBank.h>
00110 #include <lal/LALNoiseModels.h>
00111 #include <lal/MatrixUtils.h>
00112 
00113 /* <lalVerbatim file="XLALInspiralComputePTFIntrinsicMetricCP">  */
00114 INT4 XLALInspiralComputePTFIntrinsicMetric (
00115     InspiralMetric                         *metric,
00116     REAL8Vector                            *fullmetric,
00117     REAL8FrequencySeries                   *psd,
00118     InspiralTemplate                       *params
00119     )
00120 /* </lalVerbatim> */
00121 {
00122   /* XLAL error handling */
00123   INT4 errcode = XLAL_SUCCESS;
00124   static const char* func = "XLALInspiralComputePTFIntrinsticMetric";
00125 
00126   /* number of points in a time-domain segment */
00127   UINT4 N = 2 * (psd->data->length - 1); 
00128   UINT4 i, j, k;
00129 
00130   /* some useful numbers */
00131   REAL4 sqrtoftwo      = sqrt(2.0);
00132   REAL4 onebysqrtoftwo = 1.0 / sqrtoftwo;
00133   REAL4 onebysqrtofsix = 1.0 / sqrt(6.0);
00134 
00135   /* get a local copy of the extrinstic parameters */
00136   REAL8 Theta = params->sourceTheta;
00137   REAL8 Phi = params->sourcePhi;
00138   REAL8 Psi = params->polarisationAngle;
00139   REAL8 phi0 = params->startPhase;
00140 
00141   /* bounds on the power spectrum integration for the moments */
00142   REAL8 deltaT = params->tSampling;
00143   REAL8 deltaF = 1.0 / ((REAL8)N * deltaT);
00144 
00145   /* local pointers to the Q and Qtilde data */
00146   REAL8                         P[5];
00147   REAL8                         PdTh[5];
00148   REAL8                         PdPh[5];
00149   REAL8                         PdPs[5];
00150   REAL8Vector                   Q[5];
00151   COMPLEX16Vector               Qtilde[5];
00152 
00153   FILE *derivsfile;
00154   /* should really check that deltaT from the template agrees with N */
00155   /* and deltaF from the power spectrum                              */
00156 
00157   /* these variables, and the memory allocation following them should be     */
00158   /* moved to a differnent function at some point in the future (preferably  */
00159   /* before this function is ever called multiple times inside a loop)       */
00160   REAL8VectorSequence                   *PTFQ;
00161   COMPLEX16VectorSequence               *PTFQtilde;
00162   REAL4Vector                           *PTFphi;
00163   REAL4Vector                           *PTFomega_2_3;
00164   REAL4VectorSequence                   *PTFe1;
00165   REAL4VectorSequence                   *PTFe2;
00166   REAL8FFTPlan                          *fwdPlan;
00167   REAL8FFTPlan                          *revPlan;
00168   COMPLEX16Vector                       *fsig0;
00169   COMPLEX16Vector                       *fsig1;
00170   COMPLEX16Vector                       *fsig;
00171   COMPLEX16Vector                       *intrinsicderiv;
00172   COMPLEX16VectorSequence               *derivs;
00173   REAL8                                  initdelta = 0.001;
00174   REAL8                                  tolerance = 0.001;
00175   REAL8Vector                           *invpsd;
00176   REAL8Vector                           *tempnorm;
00177   COMPLEX16Vector                       *tempnormtilde;
00178   REAL8                                  wavenorm;
00179   REAL8Array                            *IntInt_matrix;
00180   REAL8Array                            *ExtExt_matrix;
00181   REAL8Array                            *ExtExt_inverse;
00182   REAL8Array                            *IntExt_matrix;  
00183   REAL8Array                            *IntExt_transp;  
00184   REAL8Array                            *matrix_5_x_4;  
00185   REAL8Array                            *matrix_4_x_4;  
00186   REAL8                                 *det;
00187   LALStatus                              status;
00188 
00189   PTFQ           = XLALCreateREAL8VectorSequence( 5, N );
00190   PTFQtilde      = XLALCreateCOMPLEX16VectorSequence( 5, N / 2 + 1 );
00191   PTFphi         = XLALCreateVector( N );
00192   PTFomega_2_3   = XLALCreateVector( N );
00193   PTFe1          = XLALCreateVectorSequence( 3, N );
00194   PTFe2          = XLALCreateVectorSequence( 3, N );
00195   fwdPlan        = XLALCreateForwardREAL8FFTPlan( N, 0 );
00196   revPlan        = XLALCreateReverseREAL8FFTPlan( N, 0 );
00197   IntInt_matrix  = XLALCreateREAL8ArrayL ( 2, 4, 4 );
00198   ExtExt_matrix  = XLALCreateREAL8ArrayL ( 2, 5, 5 );
00199   ExtExt_inverse = XLALCreateREAL8ArrayL ( 2, 5, 5 );
00200   IntExt_matrix  = XLALCreateREAL8ArrayL ( 2, 4, 5 );
00201   IntExt_transp  = XLALCreateREAL8ArrayL ( 2, 5, 4 );
00202   matrix_5_x_4   = XLALCreateREAL8ArrayL ( 2, 5, 4 );
00203   matrix_4_x_4   = XLALCreateREAL8ArrayL ( 2, 4, 4 );
00204   
00205   det            = NULL;
00206 
00207   memset( &status, 0, sizeof(LALStatus) );
00208 
00209   /* call the PTF waveform code */
00210   errcode = XLALFindChirpPTFWaveform( PTFphi, PTFomega_2_3, PTFe1, PTFe2,
00211       params, deltaT);
00212 
00213   if ( errcode != XLAL_SUCCESS ) XLAL_ERROR( func, errcode );
00214 
00215   /* point the dummy variables Q and Qtilde to the actual output structures */
00216   for ( i = 0; i < 5; ++i )
00217   {
00218     Q[i].length      = N;
00219     Qtilde[i].length = N / 2 + 1;
00220     Q[i].data        = PTFQ->data + (i * N);
00221     Qtilde[i].data   = PTFQtilde->data + (i * (N / 2 + 1)) ;
00222   }  
00223 
00224   /* evaluate the Q^I factors from the dynamical variables */
00225   for ( j = 0; j < N; ++j )
00226   {
00227     REAL8 omega_2_3 = PTFomega_2_3->data[j];
00228     REAL8 phi       = PTFphi->data[j];
00229     REAL8 e1x       = PTFe1->data[j];
00230     REAL8 e1y       = PTFe1->data[N + j];
00231     REAL8 e1z       = PTFe1->data[2 * N + j]; 
00232     REAL8 e2x       = PTFe2->data[j];
00233     REAL8 e2y       = PTFe2->data[N + j];
00234     REAL8 e2z       = PTFe2->data[2 * N + j];
00235 
00236     Q[0].data[j] = omega_2_3 * onebysqrtoftwo * ( cos(2 * phi) * ( e1x * e1x +
00237           e2y * e2y - e2x * e2x - e1y * e1y ) + 2 * sin(2 * phi) *
00238         ( e1x * e2x - e1y * e2y ));
00239     Q[1].data[j] = omega_2_3 * sqrtoftwo * ( cos(2 * phi) * ( e1x * e1y - 
00240           e2x * e2y ) + sin(2 * phi) * ( e1x * e2y + e1y * e2x ));
00241     Q[2].data[j] = omega_2_3 * sqrtoftwo * ( cos(2 * phi) * ( e1x * e1z - 
00242           e2x * e2z ) + sin(2 * phi) * ( e1x * e2z + e1z * e2x ));
00243     Q[3].data[j] = omega_2_3 * sqrtoftwo * ( cos(2 * phi) * ( e1y * e1z - 
00244           e2y * e2z ) + sin(2 * phi) * ( e1y * e2z + e1z * e2y ));
00245     Q[4].data[j] = omega_2_3 * onebysqrtofsix * ( cos(2 * phi) * 
00246         ( 2 * e2z * e2z - 2 * e1z * e1z + e1x * e1x + e1y * e1y - 
00247           e2x * e2x - e2y * e2y ) + 2 * sin(2 * phi) * ( e1x * e2x +
00248             e1y * e2y - 2 * e1z * e2z ));                              
00249   }
00250 
00251   /* Fourier transform the Q's into the Qtilde's */
00252   for ( i = 0; i < 5; ++i )
00253   {
00254     XLALREAL8ForwardFFT( &Qtilde[i], &Q[i], fwdPlan);
00255   }
00256 
00257   /* evaluate the P_I factors from the extrinsic parameters */
00258   P[0] = -(1 + cos(Theta) * cos(Theta)) * cos(2 * Phi) * cos(Psi) 
00259     + 2 * cos(Theta) * sin(2 * Phi) * sin(Psi);
00260   P[1] = - 2 * cos(Theta) * cos(2 * Phi) * sin(Psi) 
00261     -(1 + cos(Theta) * cos(Theta)) * sin(2 * Phi) * cos(Psi);
00262   P[2] = 2 * sin(Theta) * (-sin(Phi) * sin(Psi) + cos(Theta) * cos(Phi) * cos(Psi));
00263   P[3] = 2 * sin(Theta) * ( cos(Phi) * sin(Psi) + cos(Theta) * sin(Phi) * cos(Psi));
00264   P[4] = 3 * sin(Theta) * sin(Theta) * cos(Psi);
00265 
00266   /* P_I derivative over Theta */
00267   PdTh[0] = -(1 - sin(2 * Theta)) * cos(2 * Phi) * cos(Psi) 
00268     - 2 * sin(Theta) * sin(2 * Phi) * sin(Psi);
00269   PdTh[1] =  2 * sin(Theta) * cos(2 * Phi) * sin(Psi) 
00270     -(1 - sin(2 * Theta)) * sin(2 * Phi) * cos(Psi);
00271   PdTh[2] = 2 * cos(Theta) * (-sin(Phi) * sin(Psi) - sin(Theta) * cos(Phi) * cos(Psi));
00272   PdTh[3] = 2 * cos(Theta) * ( cos(Phi) * sin(Psi) - sin(Theta) * sin(Phi) * cos(Psi));
00273   PdTh[4] = 3 * sin(2 * Theta) * cos(Psi);
00274 
00275   /* P_I derivative over Phi */
00276   PdPh[0] = - 2 * (1 + cos(Theta) * cos(Theta)) * sin(2 * Phi) * cos(Psi) 
00277     + 4 * cos(Theta) * cos(2 * Phi) * sin(Psi);
00278   PdPh[1] =   4 * cos(Theta) * sin(2 * Phi) * sin(Psi) 
00279     - 2 * (1 + cos(Theta) * cos(Theta)) * cos(2 * Phi) * cos(Psi);
00280   PdPh[2] = 2 * sin(Theta) * (-cos(Phi) * sin(Psi) - cos(Theta) * sin(Phi) * cos(Psi));
00281   PdPh[3] = 2 * sin(Theta) * (-sin(Phi) * sin(Psi) + cos(Theta) * cos(Phi) * cos(Psi));
00282   PdPh[4] = 0;
00283 
00284   /* P_I derivative over Psi */
00285   PdPs[0] = (1 + cos(Theta) * cos(Theta)) * cos(2 * Phi) * sin(Psi) 
00286     + 2 * cos(Theta) * sin(2 * Phi) * cos(Psi);
00287   PdPs[1] = - 2 * cos(Theta) * cos(2 * Phi) * cos(Psi) 
00288     + (1 + cos(Theta) * cos(Theta)) * sin(2 * Phi) * sin(Psi);
00289   PdPs[2] = 2 * sin(Theta) * (-sin(Phi) * cos(Psi) - cos(Theta) * cos(Phi) * sin(Psi));
00290   PdPs[3] = 2 * sin(Theta) * ( cos(Phi) * cos(Psi) - cos(Theta) * sin(Phi) * sin(Psi));
00291   PdPs[4] = - 3 * sin(Theta) * sin(Theta) * sin(Psi);
00292 
00293   /* Prepare frequency domain signals */
00294   fsig0 = XLALCreateCOMPLEX16Vector(N / 2 + 1);
00295   fsig1 = XLALCreateCOMPLEX16Vector(N / 2 + 1);
00296   fsig  = XLALCreateCOMPLEX16Vector(N / 2 + 1);
00297 
00298   for (k = 0; k < N / 2 + 1; ++k)
00299   {
00300     fsig0->data[k].re = 0.0;
00301     fsig0->data[k].im = 0.0;
00302     fsig1->data[k].re = 0.0;
00303     fsig1->data[k].im = 0.0;
00304     for (i = 0; i < 5; ++i)
00305     {
00306       fsig0->data[k].re += P[i] * Qtilde[i].data[k].re;
00307       fsig0->data[k].im += P[i] * Qtilde[i].data[k].im;
00308     }
00309     fsig1->data[k].re =   fsig0->data[k].im;
00310     fsig1->data[k].im = - fsig0->data[k].re;
00311   }
00312   fsig1->data[0].re             = fsig0->data[0].re;
00313   fsig1->data[0].im             = fsig0->data[0].im;
00314   fsig1->data[N / 2].re = fsig0->data[N / 2].re;
00315   fsig1->data[N / 2].im = fsig0->data[N / 2].im;
00316   for (k = 0; k < N / 2 + 1; ++k)
00317   {
00318     fsig->data[k].re = cos(phi0) * fsig0->data[k].re + sin(phi0) * fsig1->data[k].re;
00319     fsig->data[k].im = cos(phi0) * fsig0->data[k].im + sin(phi0) * fsig1->data[k].im;
00320   }
00321 
00322   /* Waveform derivatives */
00323   intrinsicderiv = XLALCreateCOMPLEX16Vector(N / 2 + 1);
00324   derivs = XLALCreateCOMPLEX16VectorSequence(9, N / 2 + 1);
00325 
00326   /* Compute extrinsic derivatives */
00327   for (k = 0; k < N / 2 + 1; ++k)
00328   {
00329     /* t0 */
00330     derivs->data[k].re = - LAL_TWOPI * deltaF * k * fsig->data[k].im;
00331     derivs->data[k].im =   LAL_TWOPI * deltaF * k * fsig->data[k].re;
00332     /* phi0 */
00333     derivs->data[N / 2 + 1 + k].re = - sin(phi0) * fsig0->data[k].re + cos(phi0) * fsig1->data[k].re;
00334     derivs->data[N / 2 + 1 + k].im = - sin(phi0) * fsig0->data[k].im + cos(phi0) * fsig1->data[k].im;
00335     /* Theta */
00336     derivs->data[N + 2 + k].re = 0.0;
00337     derivs->data[N + 2 + k].im = 0.0;
00338     for (i = 0; i < 5; ++i)
00339     {
00340       derivs->data[N + 2 + k].re += PdTh[i] * Qtilde[i].data[k].re;
00341       derivs->data[N + 2 + k].im += PdTh[i] * Qtilde[i].data[k].im;
00342     }
00343     /* Phi */
00344     derivs->data[3 * N / 2 + 3 + k].re = 0.0;
00345     derivs->data[3 * N / 2 + 3 + k].im = 0.0;
00346     for (i = 0; i < 5; ++i)
00347     {
00348       derivs->data[3 * N / 2 + 3 + k].re += PdPh[i] * Qtilde[i].data[k].re;
00349       derivs->data[3 * N / 2 + 3 + k].im += PdPh[i] * Qtilde[i].data[k].im;
00350     }
00351     /* Psi */
00352     derivs->data[2 * N + 4 + k].re = 0.0;
00353     derivs->data[2 * N + 4 + k].im = 0.0;
00354     for (i = 0; i < 5; ++i)
00355     {
00356       derivs->data[2 * N + 4 + k].re += PdPs[i] * Qtilde[i].data[k].re;
00357       derivs->data[2 * N + 4 + k].im += PdPs[i] * Qtilde[i].data[k].im;
00358     }
00359   }
00360 
00361   /* Compute intrinsic derivatives */
00362   for (i = 5; i < 9; ++i)
00363   {
00364     errcode = XLALInspiralComputePTFWDeriv(intrinsicderiv, psd, params, i - 4, initdelta, tolerance);
00365     if ( errcode != XLAL_SUCCESS )
00366     {
00367       fprintf( stderr, "XLALInspiralComputePTFDeriv failed\n" );
00368       exit( 1 );
00369     }
00370     for (k = 0; k < N / 2 + 1; ++k)
00371     {
00372       derivs->data[i * (N / 2 + 1) + k].re = cos(phi0) * intrinsicderiv->data[k].re
00373         + sin(phi0) * intrinsicderiv->data[k].im;
00374       derivs->data[i * (N / 2 + 1) + k].im = cos(phi0) * intrinsicderiv->data[k].im
00375         - sin(phi0) * intrinsicderiv->data[k].re;
00376     }
00377     derivs->data[i * (N / 2 + 1)].re = (cos(phi0) + sin(phi0)) * intrinsicderiv->data[0].re;
00378     derivs->data[i * (N / 2 + 1)].im = (cos(phi0) + sin(phi0)) * intrinsicderiv->data[0].im;
00379     derivs->data[i * (N / 2 + 1) + N / 2].re = (cos(phi0) + sin(phi0)) * intrinsicderiv->data[N / 2].re;
00380     derivs->data[i * (N / 2 + 1) + N / 2].im = (cos(phi0) + sin(phi0)) * intrinsicderiv->data[N / 2].im;
00381   }
00382 
00383 
00384   derivsfile = fopen( "myderivs.dat", "w" );
00385 
00386   if( derivsfile != NULL )
00387   {
00388     for (j = 0; j < N / 2 + 1; ++j)
00389     {
00390       fprintf( derivsfile, "%f   %f   %f   %f   %f   %f   %f   %f   %f   %f   %f   %f   %f   %f   %f   %f   %f   %f\n", 
00391           derivs->data[j].re, derivs->data[j].im, 
00392           derivs->data[(N / 2 + 1) + j].re, derivs->data[(N / 2 + 1) + j].im, 
00393           derivs->data[2 * (N / 2 + 1) + j].re, derivs->data[2 * (N / 2 + 1) + j].im, 
00394           derivs->data[3 * (N / 2 + 1) + j].re, derivs->data[3 * (N / 2 + 1) + j].im, 
00395           derivs->data[4 * (N / 2 + 1) + j].re, derivs->data[4 * (N / 2 + 1) + j].im, 
00396           derivs->data[5 * (N / 2 + 1) + j].re, derivs->data[5 * (N / 2 + 1) + j].im, 
00397           derivs->data[6 * (N / 2 + 1) + j].re, derivs->data[6 * (N / 2 + 1) + j].im, 
00398           derivs->data[7 * (N / 2 + 1) + j].re, derivs->data[7 * (N / 2 + 1) + j].im, 
00399           derivs->data[8 * (N / 2 + 1) + j].re, derivs->data[8 * (N / 2 + 1) + j].im);
00400     }
00401   }
00402   fclose(derivsfile);
00403 
00404   /* Compute full metric */
00405   invpsd                = XLALCreateREAL8Vector(N / 2 + 1);
00406   tempnorm              = XLALCreateREAL8Vector(N);
00407   tempnormtilde = XLALCreateCOMPLEX16Vector(N / 2 + 1);
00408 
00409   for (k = 0; k < N / 2 + 1; ++k)
00410   {
00411     if (psd->data->data[k] == 0.)
00412       invpsd->data[k] = 0.;
00413     else
00414       invpsd->data[k] = 1.0 / psd->data->data[k];
00415   }
00416 
00417   for (i = 0; i < 9; ++i)
00418   {
00419     for (j = 0; j < i + 1; ++j)
00420     { 
00421       for (k = 0; k < N / 2 + 1; ++k)
00422       {
00423         tempnormtilde->data[k].re = 
00424           ( derivs->data[i * (N/2+1) + k].re * derivs->data[j * (N/2+1) + k].re
00425             + derivs->data[i * (N/2+1) + k].im * derivs->data[j * (N/2+1) + k].im) 
00426           * invpsd->data[k];
00427         tempnormtilde->data[k].im = 
00428           ( derivs->data[i * (N/2+1) + k].im * derivs->data[j * (N/2+1) + k].re
00429             - derivs->data[i * (N/2+1) + k].re * derivs->data[j * (N/2+1) + k].im) 
00430           * invpsd->data[k];
00431       }
00432       /* Inverse Fourier of tempnorm */
00433       XLALREAL8ReverseFFT(tempnorm, tempnormtilde, revPlan);
00434       fullmetric->data[i * (i + 1) / 2 + j] = 4.0 * tempnorm->data[0];
00435     }
00436   }
00437 
00438   wavenorm = fullmetric->data[2];
00439   for (i = 0; i < 45; ++i)
00440   {
00441     fullmetric->data[i] /= wavenorm;
00442   }
00443   
00444   /* Calculating the extrinsic-extrinsic block of the metric */
00445   for (i = 0; i < 5; ++i)
00446   {
00447     for (j = 0; j < i + 1; ++j)
00448     {  
00449       ExtExt_matrix->data[ 5 * i + j] = ExtExt_matrix->data[ 5 * j + i] = 
00450         fullmetric->data[i * (i + 1) / 2 + j];
00451     }  
00452   } 
00453   
00454   /* Calculating the inverse of ext-ext */
00455   LALDMatrixInverse( &status, det, ExtExt_matrix, ExtExt_inverse );
00456   if ( status.statusCode )
00457   {
00458     REPORTSTATUS( &status );
00459     exit( 1 );
00460   }
00461   
00462   /* Calculating the intrinsic-intrinsic block of the metric */
00463   for (i = 5; i < 9; ++i)
00464   {
00465     for (j = 5; j < i + 1; ++j)
00466     {  
00467       IntInt_matrix->data[ 4 * (i-5) + j - 5] = IntInt_matrix->data[ 4 * (j-5) + i - 5]= 
00468         fullmetric->data[i * (i + 1) / 2 + j];
00469     }  
00470   } 
00471   
00472   /* Calculating the mixed intrinsic-extrinsic block of the metric */
00473   for (i = 5; i < 9; ++i)
00474   {
00475     for (j = 0; j < 5; ++j)
00476     {
00477       IntExt_matrix->data[ 5 * (i-5) + j] = fullmetric->data[i * (i + 1) / 2 + j];
00478     }  
00479   } 
00480   
00481   /* Calculating the transpose of int-ext */
00482   LALDMatrixTranspose ( &status, IntExt_transp, IntExt_matrix );
00483   if ( status.statusCode )
00484   {
00485     REPORTSTATUS( &status );
00486     exit( 1 );
00487   }
00488 
00489   for (i = 0; i < 5; ++i)
00490   {
00491     for (j=0; j < 4; ++j)
00492     {
00493       IntExt_transp->data[ 4 * i + j] = IntExt_matrix->data[ j * 5 + i];
00494     }
00495   }
00496 
00497   /* Compute the projected metric from eq.(72) of PBCV*/
00498 
00499   LALDMatrixMultiply ( &status, matrix_5_x_4, ExtExt_inverse, IntExt_transp );
00500   if ( status.statusCode )
00501   {
00502     REPORTSTATUS( &status );
00503     exit( 1 );
00504   }
00505   
00506   LALDMatrixMultiply ( &status, matrix_4_x_4, IntExt_matrix, matrix_5_x_4 );
00507   if ( status.statusCode )
00508   {
00509     REPORTSTATUS( &status );
00510     exit( 1 );
00511   }
00512   
00513   for ( i = 0; i < 4; ++i )
00514   {
00515     for ( j = 0; j < i + 1; ++j )
00516     {
00517       params->Gamma[i * (i + 1) / 2 + j] = metric->Gamma[i * (i + 1) / 2 + j] = 
00518         IntInt_matrix->data[i * 4 + j] - matrix_4_x_4->data[i * 4 + j];
00519     }
00520   }
00521   
00522   /* this memory deallocation code should be moved to a separate function */
00523   XLALDestroyCOMPLEX16Vector(fsig0);
00524   XLALDestroyCOMPLEX16Vector(fsig1);
00525   XLALDestroyCOMPLEX16Vector(fsig);
00526   XLALDestroyCOMPLEX16Vector(intrinsicderiv);
00527   XLALDestroyCOMPLEX16VectorSequence(derivs);
00528   XLALDestroyCOMPLEX16Vector(tempnormtilde);
00529   XLALDestroyREAL8Vector(tempnorm);
00530   XLALDestroyREAL8VectorSequence( PTFQ );
00531   XLALDestroyCOMPLEX16VectorSequence( PTFQtilde );
00532   XLALDestroyVector( PTFphi );
00533   XLALDestroyVector( PTFomega_2_3 );
00534   XLALDestroyVectorSequence( PTFe1 );
00535   XLALDestroyVectorSequence( PTFe2 );
00536   XLALDestroyREAL8FFTPlan( fwdPlan );
00537   XLALDestroyREAL8FFTPlan( revPlan );
00538   XLALDestroyREAL8Array( IntInt_matrix );
00539   XLALDestroyREAL8Array( ExtExt_matrix );
00540   XLALDestroyREAL8Array( IntExt_matrix );
00541   XLALDestroyREAL8Array( IntExt_transp );
00542   XLALDestroyREAL8Array( ExtExt_inverse );
00543   XLALDestroyREAL8Array( matrix_5_x_4 );
00544   XLALDestroyREAL8Array( matrix_4_x_4 );
00545   
00546   /* normal exit */
00547   return errcode;
00548 }
00549 
00550 /* <lalVerbatim file="XLALInspiralComputePTFFullMetricCP">  */
00551 INT4 XLALInspiralComputePTFFullMetric (
00552     InspiralMetric             *metric,
00553     REAL8FrequencySeries       *psd,
00554     InspiralTemplate           *params
00555     )
00556 /* </lalVerbatim> */
00557 {
00558   return XLAL_SUCCESS;
00559 }
00560 
00561 
00562 /* <lalVerbatim file="XLALInspiralComputePTFWaveformCP">  */
00563 INT4 XLALInspiralComputePTFWaveform (
00564     REAL8Vector                            *ptfwave,
00565     InspiralTemplate           *params
00566     )
00567 /* </lalVerbatim> */
00568 {
00569   /* XLAL error handling */
00570   INT4 errcode = XLAL_SUCCESS;
00571   static const char* func = "XLALInspiralComputePTFWaveform";
00572 
00573   /* number of points in a time-domain segment */
00574   UINT4 N = ptfwave->length; 
00575   UINT4 i, j;
00576 
00577   /* some useful numbers */
00578   REAL8 sqrtoftwo      = sqrt(2.0);
00579   REAL8 onebysqrtoftwo = 1.0 / sqrtoftwo;
00580   REAL8 onebysqrtofsix = 1.0 / sqrt(6.0);
00581 
00582   /* get a local copy of the extrinstic parameters */
00583   REAL8 Theta = params->sourceTheta;
00584   REAL8 Phi = params->sourcePhi;
00585   REAL8 Psi = params->polarisationAngle;
00586   REAL8 phi0 = params->startPhase;
00587 
00588   /* bounds on the power spectrum integration for the moments */
00589   REAL8 deltaT = params->tSampling;
00590 
00591   /* P-factors */
00592   REAL8 P[5];
00593   /* local pointers to the Q and Qtilde data */
00594   REAL8Vector Q[5];
00595   REAL8Vector Qp[5];
00596 
00597   /* should really check that deltaT from the template agrees with N */
00598   /* and deltaF from the power spectrum                              */
00599 
00600   /* these variables, and the memory allocation following them should be     */
00601   /* moved to a differnent function at some point in the future (preferably  */
00602   /* before this function is ever called multiple times inside a loop)       */
00603   REAL8VectorSequence          *PTFQ;
00604   REAL8VectorSequence          *PTFQp;
00605   REAL4Vector                  *PTFphi;
00606   REAL4Vector                  *PTFomega_2_3;
00607   REAL4VectorSequence          *PTFe1;
00608   REAL4VectorSequence          *PTFe2;
00609   REAL8FFTPlan                  *fwdPlan;
00610 
00611   PTFQ = XLALCreateREAL8VectorSequence( 5, N );
00612   PTFQp = XLALCreateREAL8VectorSequence( 5, N );
00613   PTFphi = XLALCreateREAL4Vector( N );
00614   PTFomega_2_3 = XLALCreateREAL4Vector( N );
00615   PTFe1 = XLALCreateREAL4VectorSequence( 3, N );
00616   PTFe2 = XLALCreateREAL4VectorSequence( 3, N );
00617   fwdPlan = XLALCreateForwardREAL8FFTPlan( N, 0 );
00618 
00619   /* call the PTF waveform code */
00620   errcode = XLALFindChirpPTFWaveform( PTFphi, PTFomega_2_3, PTFe1, PTFe2,
00621       params, deltaT);
00622 
00623   if ( errcode != XLAL_SUCCESS ) XLAL_ERROR( func, errcode );
00624   
00625   /* point the dummy variables Q and Qp to the actual output structures */
00626   for ( i = 0; i < 5; ++i )
00627   {
00628     Q[i].length      = N;
00629     Qp[i].length     = N;
00630     Q[i].data        = PTFQ->data + (i * N);
00631     Qp[i].data       = PTFQp->data + (i * N);
00632   }  
00633   
00634   /* evaluate the Q^I factors from the dynamical variables */
00635   for ( j = 0; j < N; ++j )
00636   {
00637     REAL8 omega_2_3 = PTFomega_2_3->data[j];
00638     REAL8 phi       = PTFphi->data[j];
00639     REAL8 e1x       = PTFe1->data[j];
00640     REAL8 e1y       = PTFe1->data[N + j];
00641     REAL8 e1z       = PTFe1->data[2 * N + j]; 
00642     REAL8 e2x       = PTFe2->data[j];
00643     REAL8 e2y       = PTFe2->data[N + j];
00644     REAL8 e2z       = PTFe2->data[2 * N + j];
00645     
00646     Q[0].data[j] = omega_2_3 * onebysqrtoftwo * ( cos(2 * phi) * ( e1x * e1x +
00647           e2y * e2y - e2x * e2x - e1y * e1y ) + 2 * sin(2 * phi) *
00648         ( e1x * e2x - e1y * e2y ));
00649     Q[1].data[j] = omega_2_3 * sqrtoftwo * ( cos(2 * phi) * ( e1x * e1y - 
00650           e2x * e2y ) + sin(2 * phi) * ( e1x * e2y + e1y * e2x ));
00651     Q[2].data[j] = omega_2_3 * sqrtoftwo * ( cos(2 * phi) * ( e1x * e1z - 
00652           e2x * e2z ) + sin(2 * phi) * ( e1x * e2z + e1z * e2x ));
00653     Q[3].data[j] = omega_2_3 * sqrtoftwo * ( cos(2 * phi) * ( e1y * e1z - 
00654           e2y * e2z ) + sin(2 * phi) * ( e1y * e2z + e1z * e2y ));
00655     Q[4].data[j] = omega_2_3 * onebysqrtofsix * ( cos(2 * phi) * 
00656         ( 2 * e2z * e2z - 2 * e1z * e1z + e1x * e1x + e1y * e1y - 
00657           e2x * e2x - e2y * e2y ) + 2 * sin(2 * phi) * ( e1x * e2x +
00658             e1y * e2y - 2 * e1z * e2z ));
00659                         
00660         Qp[0].data[j] = omega_2_3 * onebysqrtoftwo * ( - sin(2 * phi) * ( e1x * e1x +
00661           e2y * e2y - e2x * e2x - e1y * e1y ) + 2 * cos(2 * phi) *
00662         ( e1x * e2x - e1y * e2y ));
00663         Qp[1].data[j] = omega_2_3 * sqrtoftwo * ( - sin(2 * phi) * ( e1x * e1y - 
00664           e2x * e2y ) + cos(2 * phi) * ( e1x * e2y + e1y * e2x ));
00665         Qp[2].data[j] = omega_2_3 * sqrtoftwo * ( - sin(2 * phi) * ( e1x * e1z - 
00666           e2x * e2z ) + cos(2 * phi) * ( e1x * e2z + e1z * e2x ));
00667         Qp[3].data[j] = omega_2_3 * sqrtoftwo * ( - sin(2 * phi) * ( e1y * e1z - 
00668           e2y * e2z ) + cos(2 * phi) * ( e1y * e2z + e1z * e2y ));
00669         Qp[4].data[j] = omega_2_3 * onebysqrtofsix * ( - sin(2 * phi) * 
00670         ( 2 * e2z * e2z - 2 * e1z * e1z + e1x * e1x + e1y * e1y - 
00671           e2x * e2x - e2y * e2y ) + 2 * cos(2 * phi) * ( e1x * e2x +
00672             e1y * e2y - 2 * e1z * e2z ));
00673   }
00674   
00675   /* evaluate the P_I factors from the extrinsic parameters */
00676   P[0] = -(1 + cos(Theta) * cos(Theta)) * cos(2 * Phi) * cos(Psi) 
00677                  + 2 * cos(Theta) * sin(2 * Phi) * sin(Psi);
00678   P[1] = - 2 * cos(Theta) * cos(2 * Phi) * sin(Psi) 
00679                  -(1 + cos(Theta) * cos(Theta)) * sin(2 * Phi) * cos(Psi);
00680   P[2] = 2 * sin(Theta) * (-sin(Phi) * sin(Psi) + cos(Theta) * cos(Phi) * cos(Psi));
00681   P[3] = 2 * sin(Theta) * ( cos(Phi) * sin(Psi) + cos(Theta) * sin(Phi) * cos(Psi));
00682   P[4] = 3 * sin(Theta) * sin(Theta) * cos(Psi);
00683   
00684   /* Build the time domain PTF waveform */
00685   /* fprintf( stdout, "initial phase: %f\n", phi0); */
00686   for ( j = 0; j < N; ++j )
00687   {
00688     ptfwave->data[j] = P[0] * ( Q[0].data[j] * cos(phi0) + Qp[0].data[j] * sin(phi0) )
00689                                          + P[1] * ( Q[1].data[j] * cos(phi0) + Qp[1].data[j] * sin(phi0) )
00690                                          + P[2] * ( Q[2].data[j] * cos(phi0) + Qp[2].data[j] * sin(phi0) )
00691                                          + P[3] * ( Q[3].data[j] * cos(phi0) + Qp[3].data[j] * sin(phi0) )
00692                                          + P[4] * ( Q[4].data[j] * cos(phi0) + Qp[4].data[j] * sin(phi0) );
00693   }
00694 
00695   /* this memory deallocation code should be moved to a separate function */
00696   XLALDestroyREAL8VectorSequence( PTFQ );
00697   XLALDestroyREAL8VectorSequence( PTFQp );
00698   XLALDestroyREAL4Vector( PTFphi );
00699   XLALDestroyREAL4Vector( PTFomega_2_3 );
00700   XLALDestroyREAL4VectorSequence( PTFe1 );
00701   XLALDestroyREAL4VectorSequence( PTFe2 );
00702   XLALDestroyREAL8FFTPlan( fwdPlan );
00703 
00704   /* normal exit */
00705   return XLAL_SUCCESS;
00706 
00707 }
00708 
00709 /* <lalVerbatim file="XLALInspiralComputePTFWDerivCP">  */
00710 INT4 XLALInspiralComputePTFWDeriv (
00711         COMPLEX16Vector                    *Wderiv,
00712         REAL8FrequencySeries       *psd,
00713     InspiralTemplate           *params,
00714         INT4                                       paramid,
00715         REAL8                                      initdelta,
00716         REAL8                                      tolerance
00717     )
00718 /* </lalVerbatim> */
00719 {
00720   /* XLAL error handling */
00721   INT4 errcode = XLAL_SUCCESS;
00722   static const char* func = "XLALInspiralComputePTFWDeriv";
00723   
00724   /* number of points in a time-domain segment */
00725   UINT4 N = (Wderiv->length - 1) * 2; 
00726   UINT4 j, k;
00727     
00728   /* get a local copy of the intrinstic parameters */
00729   REAL8 totalMass = params->totalMass;
00730   REAL8 eta = params->eta;
00731   REAL8 chi = params->chi;
00732   REAL8 kappa = params->kappa;
00733 
00734   /* bounds on the power spectrum integration for the moments */
00735   REAL8 deltaT = params->tSampling;
00736   
00737   /* deviated template parameters */
00738   InspiralTemplate pparams = *params;
00739   InspiralTemplate mparams = *params;
00740   
00741   /* Waveform length recorder */
00742   UINT4 clen, plen, mlen;
00743   INT4 dlen;
00744   
00745   /* local pointers to the waveforms data */
00746   /* this memory deallocation code should be moved to a separate function */
00747   REAL8Vector                           *cwave;
00748   REAL8Vector                           *pwavenew;
00749   REAL8Vector                           *mwavenew;
00750   REAL8Vector                           *pwaveold;
00751   REAL8Vector                           *mwaveold;
00752   REAL8Vector                           *pwaveold2;
00753   REAL8Vector                           *mwaveold2;
00754   REAL8Vector                           *wavederivnew;
00755   REAL8Vector                           *wavederivold;
00756   REAL8Vector                           *wavederivdiff;
00757   REAL8Vector                           *wavederiv_2;
00758   REAL8Vector                           *wavederivdiff_2;
00759   COMPLEX16Vector                       *derivtilde;
00760   COMPLEX16Vector                       *derivdifftilde;
00761   COMPLEX16Vector                       *derivpowertilde;
00762   COMPLEX16Vector                       *derivdiffpowertilde;
00763   REAL8FFTPlan                          *fwdPlan;
00764   REAL8FFTPlan                          *revPlan;
00765   UINT4 iter = 1;
00766   UINT4 maxiter = 20;
00767   REAL8 reldelta = initdelta;
00768   REAL8 absdelta;
00769   REAL8 relderivdiff = 1.0;
00770   REAL8 relderivdifflist[20];
00771   REAL8 invpsd;
00772   REAL8 powerderiv;
00773   REAL8 powerderivdiff;
00774 
00775   LALStatus status;
00776   memset( &status, 0, sizeof(LALStatus) );
00777   pparams.massChoice = totalMassAndEta;
00778   mparams.massChoice = totalMassAndEta;
00779   
00780   cwave = XLALCreateREAL8Vector( N );
00781   pwavenew = XLALCreateREAL8Vector( N );
00782   mwavenew = XLALCreateREAL8Vector( N );
00783   pwaveold = XLALCreateREAL8Vector( N );
00784   mwaveold = XLALCreateREAL8Vector( N );
00785   pwaveold2 = XLALCreateREAL8Vector( N );
00786   mwaveold2 = XLALCreateREAL8Vector( N );
00787   wavederivnew = XLALCreateREAL8Vector( N );
00788   wavederivold = XLALCreateREAL8Vector( N );
00789   wavederivdiff = XLALCreateREAL8Vector( N );
00790   wavederiv_2 = XLALCreateREAL8Vector( N );
00791   wavederivdiff_2 = XLALCreateREAL8Vector( N );
00792   derivtilde = XLALCreateCOMPLEX16Vector( N / 2 + 1 );
00793   derivdifftilde = XLALCreateCOMPLEX16Vector( N / 2 + 1 );
00794   derivpowertilde = XLALCreateCOMPLEX16Vector( N / 2 + 1 );
00795   derivdiffpowertilde = XLALCreateCOMPLEX16Vector( N / 2 + 1 );
00796   fwdPlan = XLALCreateForwardREAL8FFTPlan( N, 0 );
00797   revPlan = XLALCreateReverseREAL8FFTPlan( N, 0 );
00798   
00799   /* main loop */
00800   
00801   /* Generate central waveform */
00802   errcode = XLALInspiralComputePTFWaveform(cwave, params);
00803   if ( errcode != XLAL_SUCCESS )
00804   {
00805         fprintf( stderr, "XLALInspiralComputePTFWaveform failed\n" );
00806         exit( 1 );
00807   }
00808   clen = params->tC / deltaT + 0.5;
00809   
00810   /* Finite differencing */
00811   while (relderivdiff > tolerance && iter < maxiter + 1)
00812   {
00813         switch (paramid)
00814         {
00815           case 1:
00816                 absdelta = totalMass * reldelta;
00817                 pparams.totalMass = totalMass + absdelta;
00818                 mparams.totalMass = totalMass - absdelta;
00819                 break;
00820           case 2:
00821                 absdelta = params->eta * reldelta;
00822                 pparams.eta               = eta           + absdelta;
00823                 mparams.eta               = eta           - absdelta;
00824                 break;
00825           case 3:
00826                 absdelta = reldelta;
00827                 pparams.chi               = chi           + absdelta;
00828                 mparams.chi               = chi           - absdelta;
00829                 break;
00830           case 4:
00831                 absdelta = reldelta;
00832                 pparams.kappa     = kappa         + absdelta;
00833                 mparams.kappa     = kappa         - absdelta;
00834                 break;
00835           default:
00836             fprintf( stdout, "XLALInspiralComputePTFWDeriv failed\n" );
00837