function [h, fPlus, fCross] = detproj(htt, detId, External)

% DETPROJ - projects waveform onto antenna patern of detector
%
% [h, fPlus, fCross] = detproj(htt, detId, External);
%
% htt        TT gauge metric perturbation
%            Source is assumed to be in the direction of the North Pole 
% detId      detector identifier string
% External   struct describing position and orientation of source wrt Earth
%            in the direction pointing from the Earth to the source
%   .x       cos source co-declination
%   .phi     source longitude
%   .psi     source's polarization angle (angle between the projection the
%            the Earth's Z axis and the source's Z axis on the transverse 
%            plane)
%
% h          signal vector in strain
% fPlus      (optional) + polarization beam pattern function
% fCross     (optional) x polarization beam pattern function
%
% SEE ALSO: GRAVEN, GETIFO

% $Id: detproj.m,v 1.15 2004/05/17 19:04:04 stuver Exp $

% INITIALIZE output variable
% CHECK inputs for errors
% DEFINE external angles from struct
% DEFINE X and Y unit vectors in souce frame from sky location
% DEFINE e+ and ex in source frame
% DEFINE e+ and ex in detector frame
% DEFINE F+ and Fx
% DETERMNINE strain at the detector

% Initialize output variable
h = [];

% Check htt and External for errors
errorcheck(htt, External);

% From the given cosine of the source's co-dec sky location, define the sine
cosTheta = External.x; 
sinTheta = sqrt(1-External.x^2);
% Define other external angles
phi = External.phi; 
psi = External.psi; 

% Define X and Y unit vectors in source frame from sky location
% (This is found from rotating about z counterclockwise angle phi and then
% rotating counterclockwise about y angle theta)
exEarth = [cos(phi)*cosTheta, sin(phi)*cosTheta, -sinTheta];
eyEarth = [-sin(phi), cos(phi), 0];
% The Z unit vector now points from the Earth to the source on the 
% line-of-sight

% Define e+ and ex in source frame
% e+ = ex'*ex - ey'*ey
ePlusEarth = (exEarth'*exEarth)-(eyEarth'*eyEarth);
% ex = ex'*ey + ey'*ex
eCrossEarth = (exEarth'*eyEarth)+(eyEarth'*exEarth);

% Define e+ and ex in detector frame
% e+@IFO = cos(2*psi)*e+ + sin(2*psi)*ex
ePlus = (cos(2*psi)*ePlusEarth)+(sin(2*psi)*eCrossEarth);
% ex@IFO = cos(2*psi)*ex - sin(2*psi)*ep
eCross = (cos(2*psi)*eCrossEarth)-(sin(2*psi)*ePlusEarth);

% Define detector projection matrix from unit vectors for the detectors arms
Cordnt = getifo(detId); % Function that returns the IFO unit vectors

% Make sure that the unit vectors are in 1x3 form
Cordnt.V = Cordnt.V(:)'; 
Cordnt.W = Cordnt.W(:)';

% D = 0.5*(Xhat'*Xhat - Yhat'*Yhat)
% where Xhat is the unit vector for the 'X' arm and Yhat is the unit vector
% for the 'Y' arm
D = 0.5*((Cordnt.V'*Cordnt.V)-(Cordnt.W'*Cordnt.W)); 

% Define F+ and Fx
% F+ = D^ij e+_ij
fPlus = trace(D*ePlus);
% Fx = D^ij ex_ij
fCross = trace(D*eCross);

% Determine strain at the detector
% h = F+*h+ + Fx*hx
h = (fPlus*htt(1,:))+(fCross*htt(2,:));

return

% ~~~ END MAIN ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

function errorcheck(htt, External)

% ERRORCHECK - checks detproj's input data for errors and stops the code if
%              an error is found
%
% errorcheck(hij, External)
%
% htt        TT gauge metric perturbation
%            Source is assumed to be in the direction of the North Pole 
% detId      detector identifier string
% External   struct describing position and orientation of source wrt Earth
%            in the direction pointing from the Earth to the source
%   .x       cos source co-declination
%   .phi     source longitude
%   .psi     source's polarization angle measured clockwise along Earth's
%            longitide from the Prime Meridian

if size(htt,1) ~= 2
    % htt must be in 2xtime format
    sizeHtt = size(htt)
    error('detproj: htt must be in 2xtime format')
end
 
% External must be a structure
if ~strcmp(class(External), 'struct')
    External
    error('detproj: External must be a structure')
end

% External must contain fields x, phi and psi
if ~isfield(External, 'x')
    External
    error('detproj: The External struct must contain the field x')
elseif abs(External.x) > 1 | ~isreal(External.x)
    % If External.x exists, it must be real and have a value between
    % -1 and 1
    External.x
    error('detproj: External.x must be real and between -1 and 1')
end
if ~isfield(External, 'phi')
    External
    error('detproj: The External struct must contain the field phi')
elseif External.phi < -pi | External.phi > pi | ~isreal(External.phi)
    % If External.phi exits, it must be real and have a value between
    % -pi and pi
    External.phi
    error(['detproj: External.phi must be real and betweeen -pi '...
            'and pi'])
end
if ~isfield(External, 'psi')
    External
    error('detproj: The External struct must contain field psi')
elseif External.psi < 0 | External.psi > (2*pi) | ...
        ~isreal(External.psi)
    % If External.psi exists, it must be real and have a value 
    % between 0 and 2*pi
    External.psi
    error('detproj: External.psi must be real and between 0 and 2*pi')
end
