void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double Jul1,Jul2;
    int retVal;

    if(nrhs!=2){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
/*Extract the input arguments.*/
    Jul1 = getDoubleFromMatlab(prhs[0]);
    Jul2 = getDoubleFromMatlab(prhs[1]);
    
/*Call the function in the SOFA library.*/
    retVal=iauTcbtdb(Jul1, Jul2, &Jul1, &Jul2);
    
    if(retVal!=0) {
        mexErrMsgTxt("An error occurred.");
    }
    
    plhs[0]=mxCreateDoubleMatrix(1,1,mxREAL);
    *(double*)mxGetData(plhs[0])=Jul1;
    if(nlhs>1) {
        plhs[1]=mxCreateDoubleMatrix(1,1,mxREAL);
        *(double*)mxGetData(plhs[1])=Jul2;
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double R, P, T, wl;
    double A,B;
    
    if(nrhs>4) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
        
    //Get the relative humidity
    if(nrhs>0&&mxGetM(prhs[0])!=0) {
       R=getDoubleFromMatlab(prhs[0]);
    } else {//Otherwise get the value from the Constants class.
       R=getScalarMatlabClassConst("Constants","standardRelHumid");
    }
    
    //Get the pressure
    if(nrhs>1&&mxGetM(prhs[1])!=0) {
        P=getDoubleFromMatlab(prhs[1]);
    } else {//Otherwise, get the value from the Constants class.
        P=getScalarMatlabClassConst("Constants","standardAtmosphericPressure");
    }
    
    //Get the temperature
    if(nrhs>2&&mxGetM(prhs[2])!=0) {
        T=getDoubleFromMatlab(prhs[2]);
    } else {//Otherwise get the value from the Constants class.
        T=getScalarMatlabClassConst("Constants","standardTemp");
    }

    //wl is inputted in meters, but needs to be in micrometers for the
    //function iauAtco13
    if(nrhs>3&&mxGetM(prhs[3])!=0) {
       wl= getDoubleFromMatlab(prhs[3]);
    } else {
       wl=0.574e-6;
    }
    
    //Convert from Pascals to millibars.
    P*=0.01;
    //Convert from degrees Kelvin to degrees Centigrade.
    T+=-273.15;
    //Convert from meters to micrometers.
    wl*=1e6;
    
    //Get the parameters for the simple refraction model.
    iauRefco(P, T, R, wl,&A, &B);
    
    //Allocate space for the return values.
    plhs[0]=doubleMat2Matlab(&A,1,1);
    if(nlhs>1) {
        plhs[1]=doubleMat2Matlab(&B,1,1);
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double *vec, *retVec, TT1,TT2;
    double rb[3][3], rp[3][3], rbp[3][3];
    mxArray *retMATLAB;
    size_t i, numItems;

    if(nrhs!=3) {
        mexErrMsgTxt("Wrong number of inputs");
        return;
    }

    if(nlhs>1) {
        mexErrMsgTxt("Wrong number of outputs");
        return;
    }

    numItems=mxGetN(prhs[0]);
    if(mxGetM(prhs[0])!=3) {
        mexErrMsgTxt("vec has the wrong dimensionality. It must be an 3XN matrix.");
        return;
    }
    checkRealDoubleArray(prhs[0]);
    vec=(double*)mxGetData(prhs[0]);

    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);

    //Allocate the return vector
    retMATLAB=mxCreateDoubleMatrix(3,numItems,mxREAL);
    retVec=mxGetData(retMATLAB);

    //Call the IAU function to get the rotation matrix.
    iauBp06(TT1, TT2, rb, rp, rbp);

    //Invert the rotation matrix by transposing it.
    iauTr(rb, rb);
    for(i=0; i<numItems; i++) {
        //Multiply the original vectors by the matrix to put it into the ICRS.
        iauRxp(rb, vec+3*i, retVec+3*i);
    }

    //Set the return value.
    plhs[0]=retMATLAB;
}
static double MatlabCallback(int n, const double *x, int *undefined_flag, void *data) {
    mxArray *rhs[2];
    mxArray *lhs[2];
    double *oldPtr;
    double fVal;
    bool violatesConstraints;

    //feval in Matlab will take the function handle and the state as
    //inputs.
    //The first function handle is f. 
    rhs[0]=(mxArray*)data;
    rhs[1]=mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);

    //Set the matrix data to x 
    oldPtr=mxGetPr(rhs[1]);
    
    //x will not be modified, but the const must be typecast away to use
    //the mxSetPr function.    
    mxSetPr(rhs[1],(double*)x);
    mxSetM(rhs[1], (size_t)n);
    mxSetN(rhs[1], 1);
    
    //Get the function value and gradient.
    mexCallMATLAB(2,lhs,2,rhs,"feval");
    
    //Get the function value.
    fVal=getDoubleFromMatlab(lhs[0]);
      
    violatesConstraints=getBoolFromMatlab(lhs[1]);
    
    if(violatesConstraints) {
        *undefined_flag=1;
    }
    
    //Get rid of the returned Matlab Matrices.
    mxDestroyArray(lhs[0]);
    mxDestroyArray(lhs[1]);
    
    //Set the data pointer back to what it was during allocation that
    //mxDestroyArray does not have a problem. 
    mxSetPr(rhs[1],oldPtr);
    mxSetM(rhs[1], 0);
    mxSetN(rhs[1], 0);
          
    //Get rid of the temporary natrix.
    mxDestroyArray(rhs[1]);

	return fVal;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    const mxArray *MatlabFunctionHandle;
    direct_algorithm theAlgorithm=DIRECT_ORIGINAL;
    const direct_objective_func f=&MatlabCallback;
    size_t numDim;
    double *lowerBounds;
    double *upperBounds;
    int maxFEval=500;
    int maxIter=100;
    double epsilon=1e-4;
    double epsilonAbs=0;
    double volumeRelTol=1e-10;
    double sigmaRelTol=0;
    double fGlobal=DIRECT_UNKNOWN_FGLOBAL;
    double fGlobalRelTol=DIRECT_UNKNOWN_FGLOBAL;
    int maxDiv=5000;
    //To hold return values
    direct_return_code retVal;
    double *x;
    double fVal;
    
    if(nrhs<3||nrhs>4){
        mexErrMsgTxt("Wrong number of inputs");
    }

    if(nlhs>3) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    //Check that a function handle was passed.
    if(!mxIsClass(prhs[0],"function_handle")) {
        mexErrMsgTxt("The first input must be a function handle.");
    }
    MatlabFunctionHandle=prhs[0];
    
    //Check the lower and upper bounds
    checkRealDoubleArray(prhs[1]);
    checkRealDoubleArray(prhs[2]);
    numDim=mxGetM(prhs[1]);
    if(numDim<1||mxGetN(prhs[1])!=1) {
        mexErrMsgTxt("The lower bounds have the wrong dimensionality.");
    }
    if(mxGetM(prhs[2])!=numDim||mxGetN(prhs[1])!=1) {
        mexErrMsgTxt("The upper bounds have the wrong dimensionality.");
    }
    
    //The function in the library only uses integers for dimensions.
    if(numDim>INT_MAX) {
        mexErrMsgTxt("The problem has too many dimensions to be solved using this function.");
    }
    
    lowerBounds=(double*)mxGetData(prhs[1]);
    upperBounds=(double*)mxGetData(prhs[2]);
    
    //If a structure of options was given
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        //We have to check for every possible structure member.
        mxArray *theField;
        
        if(!mxIsStruct(prhs[3])) {
            mexErrMsgTxt("The options must be given in a structure.");
        }
    
        theField=mxGetField(prhs[3],0,"algorithm");
        
        if(theField!=NULL) {//If the field is present.
            int algType=getIntFromMatlab(theField);
            
            //Algorithm type
            switch(algType) {
              case 0:
                  theAlgorithm=DIRECT_ORIGINAL;
                  break;
              case 1:
                  theAlgorithm=DIRECT_GABLONSKY;
                  break;
              default:
                  mexErrMsgTxt("Invalid algorithm specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"maxDiv");
        if(theField!=NULL) {//If the field is present.
            maxDiv=getIntFromMatlab(theField);
            if(maxDiv<1) {
                mexErrMsgTxt("Invalid maxDiv specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"maxIter");
        if(theField!=NULL) {//If the field is present.
            maxIter=getIntFromMatlab(theField);
            if(maxIter<1) {
                mexErrMsgTxt("Invalid maxIter specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"maxFEval");
        if(theField!=NULL) {//If the field is present.
            maxFEval=getIntFromMatlab(theField);
            if(maxIter<1) {
                mexErrMsgTxt("Invalid maxFEval specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"epsilon");
        if(theField!=NULL) {//If the field is present.
            epsilon=getDoubleFromMatlab(theField);
            if(fabs(epsilon)>=1) {
                mexErrMsgTxt("Invalid epsilon specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"epsilonAbs");
        if(theField!=NULL) {//If the field is present.
            epsilonAbs=getDoubleFromMatlab(theField);
            if(epsilonAbs>=1||epsilonAbs<0) {
                mexErrMsgTxt("Invalid epsilonAbs specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"volumeRelTol");
        if(theField!=NULL) {//If the field is present.
            volumeRelTol=getDoubleFromMatlab(theField);
            if(volumeRelTol>=1||volumeRelTol<0) {
                mexErrMsgTxt("Invalid volumeRelTol specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"sigmaRelTol");
        if(theField!=NULL) {//If the field is present.
            sigmaRelTol=getDoubleFromMatlab(theField);
            if(sigmaRelTol>=1||sigmaRelTol<0) {
                mexErrMsgTxt("Invalid sigmaRelTol specified");
            }
        }
        
        theField=mxGetField(prhs[3],0,"fGlobal");
        if(theField!=NULL) {//If the field is present.
            fGlobal=getDoubleFromMatlab(theField);
            fGlobalRelTol=1e-12;//Default value if fGlobal is given.
        }
        
        theField=mxGetField(prhs[3],0,"fGlobalRelTol");
        if(theField!=NULL) {//If the field is present.
            fGlobalRelTol=getDoubleFromMatlab(theField);
            if(fGlobalRelTol<0) {
                mexErrMsgTxt("Invalid fGlobalRelTol specified");
            }
        }      
    }
    
    //Allocate space for the return values
    x=mxCalloc(numDim, sizeof(double));

    retVal=direct_optimize(f,//Objective function pointer
            (void*)MatlabFunctionHandle,//Data that passed to the objective function. Here, the function handle passed by the user.
            (int)numDim,//The dimensionality of the problem
            lowerBounds,//Array of the lower bound of each dimension.
            upperBounds,//Array of the upper bound of each dimension.
            x,//An array that will be set to the optimum value on return.
            &fVal,//On return, set to the minimum value.
            maxFEval,//Maximum number of function evaluations.
            maxIter,//Maximum number of iterations
            epsilon,//Jones' epsilon parameter (1e-4 is recommended)
            epsilonAbs,//An absolute version of magic_eps
            //Relative tolerance on the hypercube volume (use 0 if none). This is
            //a percentage (0-1) of the volume of the original hypercube
            volumeRelTol,
            //Relative tolerance on the hypercube measure (0 if none)
            sigmaRelTol,
            //A pointer to a variable that can terminate the optimization. This is
            //in the library's code so that an external thread can write to this
            //and force the optimization to stop. Here, we are not using it, so we
            //can pass NULL.
            NULL,
            fGlobal,//Function value of the global optimum, if known. Use DIRECT_UNKNOWN_FGLOBAL if unknown.
            fGlobalRelTol,//Relative tolerance for convergence if fglobal is known. If unknown, use DIRECT_UNKNOWN_FGLOBAL.
            NULL,//There is no output to a file.
            theAlgorithm,//The algorithm to use
            maxDiv);//The maximum number of hyperrectangle divisions

    //If an error occurred
    if(retVal<0) {
        mxFree(x);
        switch(retVal){
            case DIRECT_INVALID_BOUNDS:
                mexErrMsgTxt("Upper bounds are <= lower bounds for one or more dimensions.");
            case DIRECT_MAXFEVAL_TOOBIG:
                mexErrMsgTxt("maxFEval is too large.");
            case DIRECT_INIT_FAILED:
                mexErrMsgTxt("An initialization step failed.");
            case DIRECT_SAMPLEPOINTS_FAILED:
                 mexErrMsgTxt("An error occurred creating sampling points.");
            case DIRECT_SAMPLE_FAILED:
                mexErrMsgTxt("An error occurred while sampling the function.");
            case DIRECT_OUT_OF_MEMORY:
                mexErrMsgTxt("Out of memory");
            case DIRECT_INVALID_ARGS:
                mexErrMsgTxt("Invalid arguments provided");
            //These errors should not occur either because they should
            //never be called or because retVal>=0 so these are not
            //actually errors.
            case DIRECT_FORCED_STOP:
            case DIRECT_MAXFEVAL_EXCEEDED:
            case DIRECT_MAXITER_EXCEEDED:
            case DIRECT_GLOBAL_FOUND:
            case DIRECT_VOLTOL:
            case DIRECT_SIGMATOL:
            case DIRECT_MAXTIME_EXCEEDED:
            default:
                mexErrMsgTxt("An unknown error occurred.");
            
        }
    }
    
    //Set the return values
    plhs[0]=mxCreateNumericMatrix(0, 0, mxDOUBLE_CLASS, mxREAL);
    mxFree(mxGetPr(plhs[0]));
    mxSetPr(plhs[0], x);
    mxSetM(plhs[0], numDim);
    mxSetN(plhs[0], 1);

    if(nlhs>1) {
        plhs[1]=doubleMat2Matlab(&fVal,1,1);
        if(nlhs>2) {
            plhs[2]=intMat2MatlabDoubles(&retVal,1,1);
        }
    }
}
void mexFunction(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[]) {
    double u, scalFactor;
    ClusterSetCPP<double> HBar;
    ClusterSetCPP<double> dHBardu;//The first derivatives
    ClusterSetCPP<double> d2HBardu2;//The second derivatives
    size_t M, numH, i;
    mxArray *CSRetVal;
    mxArray *clusterElsMATLAB,*clusterSizesMATLAB, *offsetArrayMATLAB;
    
    if(nrhs!=3){
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }

    u=getDoubleFromMatlab(prhs[0]);
    M=getSizeTFromMatlab(prhs[1]);
    scalFactor=getDoubleFromMatlab(prhs[2]);
    
    if(M<3) {
       mexErrMsgTxt("The maximum order should be at least 3.");
       return; 
    }
    
    numH=(M+1)*(M+2)/2;
    
    //Allocate space for the results.
    clusterElsMATLAB=mxCreateDoubleMatrix(numH,1,mxREAL);
    clusterSizesMATLAB=allocUnsignedSizeMatInMatlab(M+1,1);
    offsetArrayMATLAB=allocUnsignedSizeMatInMatlab(M+1,1);
    
    HBar.numClust=M+1;
    HBar.totalNumEl=numH;
    HBar.clusterEls=reinterpret_cast<double*>(mxGetData(clusterElsMATLAB));
    HBar.offsetArray=reinterpret_cast<size_t*>(mxGetData(offsetArrayMATLAB));
    HBar.clusterSizes=reinterpret_cast<size_t*>(mxGetData(clusterSizesMATLAB));
    
    //Initialize the offset array and cluster sizes.
    HBar.offsetArray[0]=0;
    HBar.clusterSizes[0]=1;
    for(i=1;i<=M;i++){
        HBar.clusterSizes[i]=i+1;
        HBar.offsetArray[i]=HBar.offsetArray[i-1]+HBar.clusterSizes[i-1];
    }
    
    normHelmHoltzCPP(HBar,u,scalFactor);
    
    //Set the first return value
    mexCallMATLAB(1,&CSRetVal,0, 0, "ClusterSet");
    mxSetProperty(CSRetVal,0,"clusterEls",clusterElsMATLAB);
    mxSetProperty(CSRetVal,0,"clusterSizes",clusterSizesMATLAB);
    mxSetProperty(CSRetVal,0,"offsetArray",offsetArrayMATLAB);
    
    plhs[0]=CSRetVal;
    
    if(nlhs>1) {//Compute the first derivatives, if they are desired.
        mxArray *clusterEls1stDerivMATLAB=mxCreateDoubleMatrix(numH,1,mxREAL);
        
        dHBardu.numClust=M+1;
        dHBardu.totalNumEl=numH;
        dHBardu.clusterEls=reinterpret_cast<double*>(mxGetData(clusterEls1stDerivMATLAB));
        dHBardu.offsetArray=reinterpret_cast<size_t*>(mxGetData(offsetArrayMATLAB));
        dHBardu.clusterSizes=reinterpret_cast<size_t*>(mxGetData(clusterSizesMATLAB));
        
        normHelmHoltzDerivCPP(dHBardu,HBar);
        //Set the second return value
        mexCallMATLAB(1,&CSRetVal,0, 0, "ClusterSet");
        mxSetProperty(CSRetVal,0,"clusterEls",clusterEls1stDerivMATLAB);
        mxSetProperty(CSRetVal,0,"clusterSizes",clusterSizesMATLAB);
        mxSetProperty(CSRetVal,0,"offsetArray",offsetArrayMATLAB);

        plhs[1]=CSRetVal;
        mxDestroyArray(clusterEls1stDerivMATLAB);
    }
    
    if(nlhs>2) {//Compute the second derivatives if they are desired.
        mxArray *clusterEls2ndDerivMATLAB=mxCreateDoubleMatrix(numH,1,mxREAL);
        
        d2HBardu2.numClust=M+1;
        d2HBardu2.totalNumEl=numH;
        d2HBardu2.clusterEls=reinterpret_cast<double*>(mxGetData(clusterEls2ndDerivMATLAB));
        d2HBardu2.offsetArray=reinterpret_cast<size_t*>(mxGetData(offsetArrayMATLAB));
        d2HBardu2.clusterSizes=reinterpret_cast<size_t*>(mxGetData(clusterSizesMATLAB));
        
        normHelmHoltzDeriv2CPP(d2HBardu2,HBar);
        
        //Set the third return value
        mexCallMATLAB(1,&CSRetVal,0, 0, "ClusterSet");
        mxSetProperty(CSRetVal,0,"clusterEls",clusterEls2ndDerivMATLAB);
        mxSetProperty(CSRetVal,0,"clusterSizes",clusterSizesMATLAB);
        mxSetProperty(CSRetVal,0,"offsetArray",offsetArrayMATLAB);

        plhs[2]=CSRetVal;
        mxDestroyArray(clusterEls2ndDerivMATLAB);
    }
    
    //Free the buffers. The mxSetProperty command copied the data.
    mxDestroyArray(clusterElsMATLAB);
    mxDestroyArray(clusterSizesMATLAB);
    mxDestroyArray(offsetArrayMATLAB);
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numRow,numVec;
    mxArray *retMat;
    double *xVec, *retData;
    double TT1, TT2, UT11, UT12;
    //The if-statements below should properly initialize all of the EOP.
    //The following initializations to zero are to suppress warnings when
    //compiling with -Wconditional-uninitialized.
    double dX=0;
    double dY=0;
    double deltaT=0;
    double LOD=0;
    double GCRS2TIRS[3][3];
    //Polar motion matrix. ITRS=POM*TIRS. We will just be setting it to the
    //identity matrix as polar motion is not taken into account when going
    //to the TIRS.
    double rident[3][3]={{1,0,0},{0,1,0},{0,0,1}};
    double Omega[3];//The rotation vector in the TIRS
    
    if(nrhs<3||nrhs>6){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    checkRealDoubleArray(prhs[0]);
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    xVec=(double*)mxGetData(prhs[0]);
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
    
    //If some values from the function getEOP will be needed
    if(nrhs<=5||mxIsEmpty(prhs[3])||mxIsEmpty(prhs[4])||mxIsEmpty(prhs[5])) {
        mxArray *retVals[5];
        double *dXdY;
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        int retVal;
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(5,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        //%We do not need the polar motion coordinates.
        mxDestroyArray(retVals[0]);
        
        checkRealDoubleArray(retVals[1]);
        if(mxGetM(retVals[1])!=2||mxGetN(retVals[1])!=1) {
            mxDestroyArray(retVals[1]);
            mxDestroyArray(retVals[2]);
            mxDestroyArray(retVals[3]);
            mxDestroyArray(retVals[4]);
            mexErrMsgTxt("Error using the getEOP function.");
            return;
        }
        
        dXdY=(double*)mxGetData(retVals[1]);
        dX=dXdY[0];
        dY=dXdY[1];
        
        //This is TT-UT1
        deltaT=getDoubleFromMatlab(retVals[3]);
        LOD=getDoubleFromMatlab(retVals[4]);
        //Free the returned arrays.
        mxDestroyArray(retVals[1]);
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(retVals[4]);
    }
    
    //If deltaT=TT-UT1 is given
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        deltaT=getDoubleFromMatlab(prhs[3]);
    }
    
    //Obtain UT1 from terestrial time and deltaT.
    iauTtut1(TT1, TT2, deltaT, &UT11, &UT12);
    
    //Get celestial pole offsets, if given.
    if(nrhs>4&&!mxIsEmpty(prhs[4])) {
        size_t dim1, dim2;
        
        checkRealDoubleArray(prhs[4]);
        dim1 = mxGetM(prhs[4]);
        dim2 = mxGetN(prhs[4]);
        
        if((dim1==2&&dim2==1)||(dim1==1&&dim2==2)) {
            double *dXdY=(double*)mxGetData(prhs[4]);
        
            dX=dXdY[0];
            dY=dXdY[1];
        } else {
            mexErrMsgTxt("The celestial pole offsets have the wrong dimensionality.");
            return;
        }
    }
    
    //If LOD is given
    if(nrhs>5&&mxIsEmpty(prhs[5])) {
        LOD=getDoubleFromMatlab(prhs[5]);
    }
    
    //Compute the rotation matrix for going from GCRS to ITRS as well as
    //the instantaneous vector angular momentum due to the Earth's rotation
    //in TIRS coordinates.
    {
    double x, y, s, era;
    double rc2i[3][3];
    double omega;
        
    //Get the X,Y coordinates of the Celestial Intermediate Pole (CIP) and
    //the Celestial Intermediate Origin (CIO) locator s, using the IAU 2006
    //precession and IAU 2000A nutation models.
    iauXys06a(TT1, TT2, &x, &y, &s);
    
    //Add the CIP offsets.
    x += dX;
    y += dY;
    
    //Get the GCRS-to-CIRS matrix
    iauC2ixys(x, y, s, rc2i);
    
    //Find the Earth rotation angle for the given UT1 time. 
    era = iauEra00(UT11, UT12);
    
    //Set the polar motion matrix to the identity matrix so that the
    //conversion stops at the TIRS instead of the ITRS.

    //Combine the GCRS-to-CIRS matrix, the Earth rotation angle, and use
    //the identity matrix instead of the polar motion matrix to get a
    //to get the rotation matrix to go from GCRS to TIRS.
    iauC2tcio(rc2i, era, rident,GCRS2TIRS);
    
    //Next, to be able to transform the velocity, the rotation of the Earth
    //has to be taken into account. 
    
    //The angular velocity vector of the Earth in the TIRS in radians.
    omega=getScalarMatlabClassConst("Constants","IERSMeanEarthRotationRate");
    //Adjust for LOD
    omega=omega*(1-LOD/86400.0);//86400.0 is the number of seconds in a TT
                                //day.
    Omega[0]=0;
    Omega[1]=0;
    Omega[2]=omega;
    }
    
    //Allocate space for the return vectors.
    retMat=mxCreateDoubleMatrix(numRow,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    
    {
        size_t curVec;
        for(curVec=0;curVec<numVec;curVec++) {
            //Multiply the position vector with the rotation matrix.
            iauRxp(GCRS2TIRS, xVec+numRow*curVec, retData+numRow*curVec);
            
            //If a velocity vector was given.
            if(numRow>3) {
                double *posGCRS=xVec+numRow*curVec;
                double posTIRS[3];
                double *velGCRS=xVec+numRow*curVec+3;//Velocity in GCRS
                double velTIRS[3];
                double *retDataVel=retData+numRow*curVec+3;
                double rotVel[3];
                //If a velocity was provided with the position, first
                //convert to TIRS coordinates, then account for the
                //rotation of the Earth.
                
                //Convert velocity from GCRS to TIRS.
                iauRxp(GCRS2TIRS, velGCRS, velTIRS);
                //Convert position from GCRS to TIRS
                iauRxp(GCRS2TIRS, posGCRS, posTIRS);
                                
                //Evaluate the cross product for the angular velocity due
                //to the Earth's rotation.
                iauPxp(Omega, posTIRS, rotVel);
                
                //Subtract out the instantaneous velocity due to rotation.
                iauPmp(velTIRS, rotVel, retDataVel);
            }
        }
    }
    plhs[0]=retMat;
    
    //If the rotation matrix is desired on the output.
    if(nlhs>1) {
        double *elPtr;
        size_t i,j;
        
        plhs[1]=mxCreateDoubleMatrix(3,3,mxREAL);
        elPtr=(double*)mxGetData(plhs[1]);
        
        for (i=0;i<3;i++) {
            for(j=0;j<3;j++) {
                elPtr[i+3*j]=GCRS2TIRS[i][j];
            }
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numRow,numVec;
    mxArray *retMat;
    double *retData;
    double ITRS2TIRS[3][3];//Inverse polar motion matrix
    double *xVec, TT1, TT2;
    double xp=0;
    double yp=0;//The polar motion coordinates
    
    if(nrhs<3||nrhs>4){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    checkRealDoubleArray(prhs[0]);
    xVec=(double*)mxGetData(prhs[0]);
    
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
    //If xpyp should be found using the function getEOP.
   if(nrhs<4||mxIsEmpty(prhs[3])) {
        mxArray *retVals[1];
        double *xpyp;
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        int retVal;
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(1,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        checkRealDoubleArray(retVals[0]);
        if(mxGetM(retVals[0])!=2||mxGetN(retVals[0])!=1) {
            mxDestroyArray(retVals[0]);
            mexErrMsgTxt("Error using the getEOP function.");
            return;
        }
        
        xpyp=(double*)mxGetData(retVals[0]);
        xp=xpyp[0];
        yp=xpyp[1];

        //Free the returned array.
        mxDestroyArray(retVals[0]);
    }
    
     //Get polar motion coordinates, if given.
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        size_t dim1, dim2;
        
        checkRealDoubleArray(prhs[3]);
        dim1 = mxGetM(prhs[3]);
        dim2 = mxGetN(prhs[3]);
        
        if((dim1==2&&dim2==1)||(dim1==1&&dim2==2)) {
            double *xpyp=(double*)mxGetData(prhs[3]);
        
            xp=xpyp[0];
            yp=xpyp[1];
        } else {
            mexErrMsgTxt("The polar motion coordinates have the wrong dimensionality.");
            return;
        }
    }

    //Get the rotation matrix from TIRS to ITRS.
    {
        double sp;
        double TIRS2ITRS[3][3];//Polar motion matrix
        //Get the Terrestrial Intermediate Origin (TIO) locator s' in
        //radians
        sp=iauSp00(TT1,TT2);
        
        //Get the polar motion matrix
        iauPom00(xp,yp,sp,TIRS2ITRS);
        
        //The inverse polar motion matrix is given by the transpose of the
        //polar motion matrix.
        iauTr(TIRS2ITRS, ITRS2TIRS); 
    }
    
    //Allocate space for the return vectors.
    retMat=mxCreateDoubleMatrix(numRow,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);

    {
    size_t curVec;
    for(curVec=0;curVec<numVec;curVec++) {
        //Multiply the position vector with the rotation matrix.
        iauRxp(ITRS2TIRS, xVec+numRow*curVec, retData+numRow*curVec);
        
        //Multiply the velocity vector with the rotation matrix.
        if(numRow>3) {
            double *velITRS=xVec+numRow*curVec+3;//Velocity in ITRS
            double *retDataVel=retData+numRow*curVec+3;//Velocity in ITRS

            //Convert velocity from ITRS to TIRS.
            iauRxp(ITRS2TIRS, velITRS, retDataVel);
        }
    }
    }

    plhs[0]=retMat;
    if(nlhs>1) {
        double *elPtr;
        size_t i,j;
        
        plhs[1]=mxCreateDoubleMatrix(3,3,mxREAL);
        elPtr=(double*)mxGetData(plhs[1]);
        
        for (i=0;i<3;i++) {
            for(j=0;j<3;j++) {
                elPtr[i+3*j]=ITRS2TIRS[i][j];
            }
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double TT1,TT2,*xVec;
    double deltaT=0;
    double LOD=0;
    size_t numRow,numVec;
    double CIRS2TIRS[3][3];
    double TIRS2CIRS[3][3];
    double Omega[3];//The rotation vector in the TIRS
    mxArray *retMat;
    double *retData;

    if(nrhs<3||nrhs>5){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    checkRealDoubleArray(prhs[0]);
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    xVec=(double*)mxGetData(prhs[0]);
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
        
    //If some values from the function getEOP will be needed
    if(nrhs<=4||mxIsEmpty(prhs[3])||mxIsEmpty(prhs[4])) {
        mxArray *retVals[5];
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        int retVal;
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(5,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        //We do not need the polar motion coordinates.
        mxDestroyArray(retVals[0]);
        //We do not need the celestial pole offsets.
        mxDestroyArray(retVals[1]);

        //This is TT-UT1
        deltaT=getDoubleFromMatlab(retVals[3]);
        LOD=getDoubleFromMatlab(retVals[4]);
        //Free the returned arrays.
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(retVals[4]);
    }

    //If deltaT=TT-UT1 is given
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        deltaT=getDoubleFromMatlab(prhs[3]);
    }
    //If LOD is given
    if(nrhs>4&&!mxIsEmpty(prhs[4])) {
        LOD=getDoubleFromMatlab(prhs[4]);
    }
    
    //Compute the rotation matrix for going from CIRS to TIRS as well as
    //the instantaneous vector angular momentum due to the Earth's rotation
    //in GCRS coordinates.
    {
        double UT11, UT12;
        double era, omega;
        //Obtain UT1 from terestrial time and deltaT.
        iauTtut1(TT1, TT2, deltaT, &UT11, &UT12);
 
        //Find the Earth rotation angle for the given UT1 time. 
        era = iauEra00(UT11, UT12);
        
        //Construct the rotation matrix.
        CIRS2TIRS[0][0]=1;
        CIRS2TIRS[0][1]=0;
        CIRS2TIRS[0][2]=0;
        CIRS2TIRS[1][0]=0;
        CIRS2TIRS[1][1]=1;
        CIRS2TIRS[1][2]=0;
        CIRS2TIRS[2][0]=0;
        CIRS2TIRS[2][1]=0;
        CIRS2TIRS[2][2]=1;     
        iauRz(era, CIRS2TIRS);
        
        //To go from the TIRS to the GCRS, we need to use the inverse rotation
        //matrix, which is just the transpose of the rotation matrix.
        iauTr(CIRS2TIRS, TIRS2CIRS);
        
        //Next, to be able to transform the velocity, the rotation of the Earth
        //has to be taken into account. 

        //The angular velocity vector of the Earth in the TIRS in radians.
        omega=getScalarMatlabClassConst("Constants","IERSMeanEarthRotationRate");
        //Adjust for LOD
        omega=omega*(1-LOD/86400.0);//86400.0 is the number of seconds in a TT
                                    //day.
        Omega[0]=0;
        Omega[1]=0;
        Omega[2]=omega;
    }
    
    //Allocate space for the return vectors.
    retMat=mxCreateDoubleMatrix(numRow,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    {
        size_t curVec;
        for(curVec=0;curVec<numVec;curVec++) {
            //Multiply the position vector with the rotation matrix.
            iauRxp(TIRS2CIRS, xVec+numRow*curVec, retData+numRow*curVec);
            
            //If a velocity vector was given.
            if(numRow>3) {
                double *posTIRS=xVec+numRow*curVec;
                double *velTIRS=xVec+numRow*curVec+3;//Velocity in GCRS
                double *retDataVel=retData+numRow*curVec+3;
                double rotVel[3];

                //Evaluate the cross product for the angular velocity due
                //to the Earth's rotation.
                iauPxp(Omega, posTIRS, rotVel);
                
                //Add the instantaneous velocity due to rotation.
                iauPpp(velTIRS, rotVel, retDataVel);
                
                //Rotate from TIRS to GCRS
                iauRxp(TIRS2CIRS, retDataVel, retDataVel);
            }
        }
    }
    plhs[0]=retMat;
    
    if(nlhs>1) {
        double *elPtr;
        size_t i,j;
        
        plhs[1]=mxCreateDoubleMatrix(3,3,mxREAL);
        elPtr=(double*)mxGetData(plhs[1]);
        
        for (i=0;i<3;i++) {
            for(j=0;j<3;j++) {
                elPtr[i+3*j]=TIRS2CIRS[i][j];
            }
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    //The Julan date in TT at the epoch used in the orbital propagation
    //algorithm: 0:00 January 1 1950
    const double epochDate=2433281.5;
    double *deltaT;
    size_t numTimes;
    double SGP4Elements[7],elementEpochTime;
    bool opsMode=0;
    char opsChar;
    bool gravityModel=0;
    gravconsttype gravConstType;
    mxArray *retMat;
    double *retVec;
    mxArray *errorMat;
    double *errorVals;

    if(nrhs<2||nrhs>6||nrhs==3) {
        mexErrMsgTxt("Incorrect number of inputs.");
        return;
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    {
        const size_t M=mxGetM(prhs[0]);
        const size_t N=mxGetN(prhs[0]);
        if(!((M==7&&N==1)||(N==7&&M==1))) {
            mexErrMsgTxt("The SGP4 elements have the wrong dimensionality.");
            return; 
        }
    }
    
    checkRealDoubleArray(prhs[0]);
    {
        size_t i;
        double *theEls;
        theEls=(double*)mxGetData(prhs[0]);
        
        //Copy the elements into SGP4Elements, adjusting the units from SI
        //to the values used here.
        for(i=0;i<5;i++) {
            SGP4Elements[i]=theEls[i];
        }
        //The multipliation by 60 changes the value from radians per second
        //to radians per minute as desired by the SGP4 code.
        SGP4Elements[5]=theEls[5]*60.0;
        SGP4Elements[6]=theEls[6];
    }
    
    {
        const size_t M=mxGetM(prhs[1]);
        const size_t N=mxGetN(prhs[1]);
        
        if((M!=1&&N!=1)||mxIsEmpty(prhs[1])) {
            mexErrMsgTxt("The times have the wrong dimensionality.");
            return;
        }
        numTimes=std::max(M,N);
    }
    checkRealDoubleArray(prhs[1]);
    deltaT=(double*)mxGetData(prhs[1]);

    if(nrhs>2&&!mxIsEmpty(prhs[2])&&!mxIsEmpty(prhs[3])) {
        const double TT1=getDoubleFromMatlab(prhs[2]);
        const double TT2=getDoubleFromMatlab(prhs[3]);
        
        if(TT1>TT2) {
            elementEpochTime=(TT1-epochDate)+TT2;
        } else {
            elementEpochTime=(TT2-epochDate)+TT1;
        }
    } else {
        //No time is given. Make sure that the deep space propagator is not
        //going to be used. Otherwise, the time value does not matter.
        elementEpochTime=0;
        
        if(2*pi/SGP4Elements[5]>=225) {
            mexErrMsgTxt("The elements imply the use of the deep space propagator, but no time was given.");
            return;  
        }
    }
    
    if(nrhs>4) {
        opsMode=getBoolFromMatlab(prhs[4]);
    }
    
    if(opsMode==0) {
        opsChar='a';
    } else {
        opsChar='i';
    }
    
    if(nrhs>5) {
        gravityModel=getBoolFromMatlab(prhs[5]);
    }
    
    if(gravityModel==0) {
        gravConstType=wgs72;
    } else {
        gravConstType=wgs84;
    }
    
    //Allocate space for the return values
    retMat=mxCreateDoubleMatrix(6,numTimes,mxREAL);
    retVec=(double*)mxGetData(retMat);
    errorMat=mxCreateDoubleMatrix(numTimes,1,mxREAL);
    errorVals=(double*)mxGetData(errorMat);
    {
        //This will be filled with the ephemeris information needed for
        //propagating the satellite.
        elsetrec satRec;
        size_t i;
        
        sgp4init(gravConstType,//Specified WGS-84 or WGS-72
                 opsChar,
                 elementEpochTime,//Epoch time of the orbital elements.
                 SGP4Elements[6],//BSTAR drag term.
                 SGP4Elements[0],//Eccentricity
                 SGP4Elements[2],//Argument of perigee
                 SGP4Elements[1],//Inclination
                 SGP4Elements[4],//Mean anomaly
                 SGP4Elements[5],//Mean motion
                 SGP4Elements[3],//Righ ascension of the ascending node.
                 satRec);//Gets filled by the function.
                
        //Do the actual propagation.
        //The division by 60 transforms the time value from seconds to
        //minutes, as the SGP4 code wants the result in minutes.
        for(i=0;i<numTimes;i++) {
            double *r=retVec+6*i;
            double *v=retVec+6*i+3;
            int j;
            
            sgp4(gravConstType, satRec,  deltaT[i]/60.0, r,  v);
            
            //Convert the units from kilometers and kilometers per second
            //to meters and meters per second.
            for(j=0;j<3;j++) {
                r[j]=1000*r[j];
                v[j]=1000*v[j];
            }
            
            errorVals[i]=(double)satRec.error;
        }
    }
    
    //Save the result
    plhs[0]=retMat;
    
    //If the error value is desired.
    if(nlhs>1) {
        plhs[1]=errorMat;
    } else{
        mxDestroyArray(errorMat);
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double TT1,TT2,TDB1,TDB2,Jul2,deltaTTUT1,deltaT,Jul1UT1, Jul2UT1,UT1Frac;
    double u, v, elon;
    int retVal;
    
    if(nrhs<2||nrhs>4){
        mexErrMsgTxt("Wrong number of inputs.");
        return;
    }

    if(nlhs>2){
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    TT1=getDoubleFromMatlab(prhs[0]);
    TT2=getDoubleFromMatlab(prhs[1]);

    //If the parameter is given and is not just an empty matrix.
    if(nrhs>2&&!(mxGetM(prhs[2])==0||mxGetN(prhs[2])==0)) {
        deltaTTUT1=getDoubleFromMatlab(prhs[2]);
    } else {
        mxArray *retVals[4];
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(4,retVals,2,JulUTCMATLAB,"getEOP");
        //This is TT-UT1
        deltaTTUT1=getDoubleFromMatlab(retVals[3]);
        //Free the returned arrays.
        mxDestroyArray(retVals[0]);
        mxDestroyArray(retVals[1]);
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
    }
    
    if(nrhs>3) {
        double *xyzClock;
        
        if(mxGetM(prhs[3])!=3||mxGetN(prhs[3])!=1) {
            mexErrMsgTxt("The dimensionality of the clock location is incorrect.");
            return;
        }
        checkRealDoubleArray(prhs[3]);
        
        xyzClock=(double*)mxGetData(prhs[3]);
        //Convert from meters to kilometers.
        xyzClock[0]/=1000;xyzClock[1]/=1000;xyzClock[2]/=1000;
        
        u=sqrt(xyzClock[0]*xyzClock[0] + xyzClock[1]*xyzClock[1]);
        v=xyzClock[2];
        elon=atan2(xyzClock[1],xyzClock[0]);
        
    } else {
        u=0;
        v=0;
        elon=0;
    }
    
    //Get UT1 
    retVal=iauTtut1(TT1, TT2, deltaTTUT1, &Jul1UT1, &Jul2UT1);
    switch(retVal) {
        case -1:
            mexErrMsgTxt("Unacceptable date provided.");
            return;
        case 1:
            mexWarnMsgTxt("Dubious year provided\n");
            break;
        default:
            break;
    }
    //Find the fraction of a Julian day in UT1
    UT1Frac=(Jul1UT1-floor(Jul1UT1))+(Jul2UT1-floor(Jul2UT1));
    UT1Frac=UT1Frac-floor(UT1Frac);

    /*Compute TDB-TT. The function iauDtdb takes TDB as an input, but we
     *only have TT. The documentation for iauDtdb says that TT can be
     *substituted within the precision limits of the function. However, an
     *extra iteration is performed here to try to make the result
     *consistent with TDB2TT to a few more digits of precision.*/
    TDB1=TT1;
    TDB2=TT2;
    {
        int curIter;
        for(curIter=0;curIter<2;curIter++) {
            deltaT = iauDtdb(TDB1, TDB2, UT1Frac, elon, u, v);

            //TT -> TDB
            retVal = iauTttdb(TT1, TT2, deltaT, &TDB1, &TDB2);
            if(retVal!=0) {
               mexErrMsgTxt("An error occured during an intermediate conversion to TDB.\n");
               return;
            }
        }
    }
    
    plhs[0]=doubleMat2Matlab(&TDB1,1, 1);
    if(nlhs>1) {
        plhs[1]=doubleMat2Matlab(&TDB2,1, 1);
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t numRow,numVec;
    mxArray *retMat;
    double *xVec, *retData;
    double TT1, TT2, UT11, UT12;
    //The if-statements below should properly initialize all of the EOP.
    //The following initializations to zero are to suppress warnings when
    //compiling with -Wconditional-uninitialized.
    double xp=0;
    double yp=0;
    double deltaT=0;
    double LOD=0;
    double ITRS2TEME[3][3];
    double PEF2TEME[3][3];
    double WInv[3][3];//The inverse polar motion matrix to go from ITRS to PEF.
    double Omega[3];//The angular velocity vector for the Earth's rotation.
    
        
    if(nrhs<3||nrhs>6){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
 
    checkRealDoubleArray(prhs[0]);
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    xVec=(double*)mxGetData(prhs[0]);
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
    
    //If some values from the function getEOP will be needed
    if(nrhs<6||mxIsEmpty(prhs[3])||mxIsEmpty(prhs[4])||mxIsEmpty(prhs[5])) {
        mxArray *retVals[5];
        double *xpyp;
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        int retVal;
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(5,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        checkRealDoubleArray(retVals[0]);
        checkRealDoubleArray(retVals[1]);
        if(mxGetM(retVals[0])!=2||mxGetN(retVals[0])!=1||mxGetM(retVals[1])!=2||mxGetN(retVals[1])!=1) {
            mxDestroyArray(retVals[0]);
            mxDestroyArray(retVals[1]);
            mxDestroyArray(retVals[2]);
            mxDestroyArray(retVals[3]);
            mxDestroyArray(retVals[4]);
            mexErrMsgTxt("Error using the getEOP function.");
            return;
        }
        
        xpyp=(double*)mxGetData(retVals[0]);
        xp=xpyp[0];
        yp=xpyp[1];
        //The celestial pole offsets are not used.
        
        //This is TT-UT1
        deltaT=getDoubleFromMatlab(retVals[3]);
        LOD=getDoubleFromMatlab(retVals[4]);
        //Free the returned arrays.
        mxDestroyArray(retVals[0]);
        mxDestroyArray(retVals[1]);
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(retVals[4]);
    }
    
    //If deltaT=TT-UT1 is given
    if(nrhs>3&&!mxIsEmpty(prhs[3])) {
        deltaT=getDoubleFromMatlab(prhs[3]);
    }
    
    //Obtain UT1 from terestrial time and deltaT.
    iauTtut1(TT1, TT2, deltaT, &UT11, &UT12);
    
    //Get polar motion values, if given.
    if(nrhs>4&&!mxIsEmpty(prhs[4])) {
        size_t dim1, dim2;
        
        checkRealDoubleArray(prhs[4]);
        dim1 = mxGetM(prhs[4]);
        dim2 = mxGetN(prhs[4]);
        
        if((dim1==2&&dim2==1)||(dim1==1&&dim2==2)) {
            double *xpyp=(double*)mxGetData(prhs[4]);
        
            xp=xpyp[0];
            yp=xpyp[1];
        } else {
            mexErrMsgTxt("The celestial pole offsets have the wrong dimensionality.");
            return;
        }
    }
    
    //If LOD is given
    if(nrhs>5&&!mxIsEmpty(prhs[5])) {
        LOD=getDoubleFromMatlab(prhs[5]);
    }

    {
     double GMST1982=iauGmst82(UT11, UT12);
     double TEME2PEF[3][3];
     double TEME2ITRS[3][3];
     double W[3][3];
     double omega;
    
     //Get Greenwhich mean sidereal time under the IAU's 1982 model. This
     //is given in radians and will be used to build a rotation matrix to
     //rotate into the PEF system.
     GMST1982=iauGmst82(UT11, UT12);
     {
         double cosGMST,sinGMST;
         cosGMST=cos(GMST1982);
         sinGMST=sin(GMST1982);
         //Build the rotation matrix to rotate by GMST about the z-axis. This
         //will put the position vector in the PEF system.
         TEME2PEF[0][0]=cosGMST;
         TEME2PEF[0][1]=sinGMST;
         TEME2PEF[0][2]=0;
         TEME2PEF[1][0]=-sinGMST;
         TEME2PEF[1][1]=cosGMST;
         TEME2PEF[1][2]=0;
         TEME2PEF[2][0]=0;
         TEME2PEF[2][1]=0;
         TEME2PEF[2][2]=1.0;
     }
     //The inverse rotation is just the transpose
     iauTr(TEME2PEF, PEF2TEME);
     //To go from PEF to ITRS, we need to build the polar motion matrix
     //using the IAU's 1980 conventions.
     {
         double cosXp,sinXp,cosYp,sinYp;
         cosXp=cos(xp);
         sinXp=sin(xp);
         cosYp=cos(yp);
         sinYp=sin(yp);
         W[0][0]=cosXp;
         W[0][1]=sinXp*sinYp;
         W[0][2]=sinXp*cosYp;
         W[1][0]=0;
         W[1][1]=cosYp;
         W[1][2]=-sinYp;
         W[2][0]=-sinXp;
         W[2][1]=cosXp*sinXp;
         W[2][2]=cosXp*cosYp;
     }
     //The inverse rotation is just the transpose
     iauTr(W, WInv);
     
     //The total rotation matrix is thus the product of the two rotations.
     //TEME2ITRS=W*TEME2PEF;
     iauRxr(W, TEME2PEF, TEME2ITRS);
     //We want the inverse rotation
     iauTr(TEME2ITRS, ITRS2TEME);
     //The angular velocity vector of the Earth in the TIRS in radians.
     omega=getScalarMatlabClassConst("Constants","IERSMeanEarthRotationRate");
     //Adjust for LOD
     omega=omega*(1-LOD/86400.0);//86400.0 is the number of seconds in a TT day.
     Omega[0]=0;
     Omega[1]=0;
     Omega[2]=omega;     
    }
    
    //Allocate space for the return vectors.
    retMat=mxCreateDoubleMatrix(numRow,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    
    {
        size_t curVec;
        
        for(curVec=0;curVec<numVec;curVec++) {
            //Multiply the position vector with the rotation matrix.
            iauRxp(ITRS2TEME, xVec+numRow*curVec, retData+numRow*curVec);
            //If a velocity vector was given.
            if(numRow>3) {
                double *posITRS=xVec+numRow*curVec;
                double *velITRS=xVec+numRow*curVec+3;//Velocity in TEME
                double posPEF[3];
                double velPEF[3];
                double *retDataVel=retData+numRow*curVec+3;
                double rotVel[3];
                //If a velocity was provided with the position, first
                //convert to PEF coordinates, then account for the rotation
                //of the Earth, then rotate into TEME coordinates.
                
                //Convert velocity from ITRS to PEF.
                iauRxp(WInv, velITRS, velPEF);
                //Convert position from ITRS to PEF
                iauRxp(WInv, posITRS, posPEF);

                //Evaluate the cross product for the angular velocity due
                //to the Earth's rotation.
                iauPxp(Omega, posPEF, rotVel);

                //Add the instantaneous velocity due to rotation.
                iauPpp(velPEF, rotVel, retDataVel);

                //Rotate from the PEF into the TEME
                iauRxp(PEF2TEME, retDataVel, retDataVel);
            }
        }
    }
    
    plhs[0]=retMat;
    
    if(nlhs>1) {
        double *elPtr;
        size_t i,j;
        
        plhs[1]=mxCreateDoubleMatrix(3,3,mxREAL);
        elPtr=(double*)mxGetData(plhs[1]);
        
        for (i=0;i<3;i++) {
            for(j=0;j<3;j++) {
                elPtr[i+3*j]=ITRS2TEME[i][j];
            }
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    size_t i, numRows,numCols, numEls;
    double minBound, maxBound, *vals, *wrapVals;
    mxArray *retMat;
    bool mirrorWrap=false;
    
    
    if(nrhs<3){
        mexErrMsgTxt("Not enough inputs.");
        return;
    }
    
    if(nrhs>4) {
        mexErrMsgTxt("Too many inputs.");
        return;
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Too many outputs.");
        return;
    }
    
    checkRealDoubleArray(prhs[0]);
    numRows=mxGetM(prhs[0]);
    numCols=mxGetN(prhs[0]);
    numEls=numRows*numCols;
    
    //If given an empty matrix, return an empty matrix.
    if(numEls==0) {
        plhs[0]=mxCreateDoubleMatrix(0,0,mxREAL);
        return;
    }
    
    vals=(double*)mxGetData(prhs[0]);
    
    minBound=getDoubleFromMatlab(prhs[1]);
    maxBound=getDoubleFromMatlab(prhs[2]);
    
    if(maxBound<=minBound) {
        mexErrMsgTxt("the maximum bound must be less than the minimum bound.");
    }
    
    if(nrhs>3) {
        mirrorWrap=getBoolFromMatlab(prhs[3]);
    }
    
    //Allocate space for the return values.
    retMat=mxCreateDoubleMatrix(numRows,numCols,mxREAL);
    wrapVals=(double*)mxGetData(retMat);
    
    if(mirrorWrap) {
        for(i=0;i<numEls;i++) {
            wrapVals[i]=wrapRangeMirrorCPP(vals[i],minBound,maxBound);
        }
    } else {
       for(i=0;i<numEls;i++) {
            wrapVals[i]=wrapRangeCPP(vals[i],minBound,maxBound);
        }
    }
    
    plhs[0]=retMat;
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double *points,a,b,b2,f,e2,eps2,ec;
    size_t numVec,i;
    mxArray *retMat;
    double *retData;
    
    if(nrhs>3||nrhs<1){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>1) {
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    checkRealDoubleArray(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(mxGetM(prhs[0])!=3) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }
    
    points=(double*)mxGetData(prhs[0]);
    //points[0] is x
    //points[1] is y
    //points[2] is z
    
    if(nrhs>1) {
        a=getDoubleFromMatlab(prhs[1]);
    } else {
        a=getScalarMatlabClassConst("Constants", "WGS84SemiMajorAxis");
    }

    if(nrhs>2) {
        f=getDoubleFromMatlab(prhs[2]);
    } else {
        f=getScalarMatlabClassConst("Constants", "WGS84Flattening");   
    }
    
    b=a*(1-f);//The semi-minor axis of the reference ellipsoid.
    b2=b*b;

    //The square of the first numerical eccentricity. 
    e2=2*f-f*f;
    //The square of the second numerical eccentricity.
    eps2=a*a/(b2)-1;

    //This value is used if Fukushima's method is chosen.
    ec=sqrt(1-e2);

    //Allocate space for the return variables.
    retMat=mxCreateDoubleMatrix(3,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    
    for(i=0;i<numVec;i++) {
        double *phi, *lambda, *h;
        double x0,y0,z0;
        double r0,p,s,q;
        
        //Get the Cartesian point to convert.
        x0=points[3*i];
        y0=points[3*i+1];
        z0=points[3*i+2];
        
        //Get the addresses of where the converted components will go
        phi=retData+3*i;
        lambda=retData+3*i+1;
        h=retData+3*i+2;
        
        r0=sqrt(x0*x0+y0*y0);
        p=fabs(z0)/eps2;
        s=r0*r0/(e2*eps2);
        q=p*p-b2+s;
    
        *lambda=atan2(y0,x0);
        if(q>=0) {//Use Sofair's algorithm
            double u,v,P,Q,t,c,w,z,Ne,val;
            
            u=p/sqrt(q);
            v=b2*u*u/q;
            P=27.0*v*s/q;
            Q=pow(sqrt(P+1.0)+sqrt(P),2.0/3.0);
            t=(1.0+Q+1/Q)/6.0;
            c=u*u-1+2*t;
            //This condition prevents finite precision problems due to
            //subtraction within the square root.
            c=fMax(c,0);
            c=sqrt(c);
            w=(c-u)/2.0;

        //The z coordinate of the closest point projected on the ellipsoid.
        //The fmax command deals with precision problems when the argument
        //is nearly zero. The problems arise due to the subtraction within
        //the square root.
            z=sqrt(t*t+v)-u*w-t/2.0-1.0/4.0;
            z=fMax(z,0);
            z=copySign(sqrt(q)*(w+sqrt(z)),z0);
            
            Ne=a*sqrt(1+eps2*z*z/b2);

            //The min and max terms deals with finite precision problems.
            val=fMin(z*(eps2+1)/Ne,1);
            val=fMax(val,-1.0);
            *phi=asin(val);
            *h=r0*cos(*phi)+z0*sin(*phi)-a*a/Ne;
        } else {//Use Fukushima's algorithm.
            double Cc,P,Z,S,C;
            //A gets a value within the loop. This initialization is just
            //to silence a warning when compiling with
            //-Wconditional-uninitialized
            double A=0;
            size_t curIter;
            const size_t maxIter=6;
            
            P=r0/a;
            Z=(ec/a)*fabs(z0);

            S=Z;
            C=ec*P;

            //Loop until convergence. Assume convergence in 6 iterations.
            for(curIter=0;curIter<maxIter;curIter++) {
                double B,F,D,SNew,CNew;
                
                A=sqrt(S*S+C*C);
                B=1.5*e2*S*C*C*((P*S-Z*C)*A-e2*S*C);
                F=P*A*A*A-e2*C*C*C;
                D=Z*A*A*A+e2*S*S*S;

                SNew=D*F-B*S;
                CNew=F*F-B*C;

                SNew=SNew/CNew;
                
                if(!isFinite(SNew)) {
                    S=SNew;
                    C=1;
                    A=sqrt(S*S+C*C);
                    break;
                } else {
                    S=SNew;
                    C=1;
                }
            }
            Cc=ec*C;

            //If the point is along the z-axis, then SNew and CNew will
            //both be zero, leading to a non-finite result.
            if(!isFinite(S)) {
                *phi=copySign(pi/2,z0);
                *h=fabs(z0)-b;
            } else {
                *phi=copySign(atan(S/Cc),z0);
                *h=(r0*Cc+fabs(z0)*S-b*A)/sqrt(Cc*Cc+S*S);
            }
        }
    }

    plhs[0]=retMat;
}
void mexFunction(const int nlhs, mxArray *plhs[], const int nrhs, const mxArray *prhs[]) {
    double a,c,scalFactor;
    double *point;
    ClusterSetCPP<double> CStdDev;
    ClusterSetCPP<double> SStdDev;
    size_t numPoints;
    size_t i, M, totalNumEls;
    mxArray *sigma2MATLAB;
    //This variable is only used if nlhs>1. It is set to zero here to
    //suppress a warning if compiled using -Wconditional-uninitialized.
    mxArray *SigmaMATLAB=NULL;
    double *sigma2,*Sigma;
    bool didOverflow;
    size_t *theOffsetArray, *theClusterSizes;
    
    if(nrhs!=6) {
        mexErrMsgTxt("Wrong number of inputs.");
    }
    
    if(nlhs>3) {
        mexErrMsgTxt("Invalid number of outputs.");
    }
    
    //Check the validity of the ClusterSets
    checkRealDoubleArray(prhs[0]);
    checkRealDoubleArray(prhs[1]);
    
    //Make sure that both of the coefficient sets have the same number of
    //elements and are not empty.
    if(mxIsEmpty(prhs[0])||mxIsEmpty(prhs[1])||mxGetM(prhs[0])!=mxGetM(prhs[1])||mxGetN(prhs[0])!=mxGetN(prhs[1])) {
        mexErrMsgTxt("Invalid ClusterSet data passed.");
    }

    CStdDev.clusterEls=reinterpret_cast<double*>(mxGetData(prhs[0]));
    SStdDev.clusterEls=reinterpret_cast<double*>(mxGetData(prhs[1]));

    //The number of elements in the ClusterSets
    totalNumEls=mxGetM(prhs[0])*mxGetN(prhs[0]);
    
    //We do not want to trust that the offset arrays and the cluster arrays
    //are valid. Also, the data types of the passed values can vary (e.g.,
    //might be doubles). Thus, we this function does not take the offset
    //and number of clusters data from a ClusterSet class. Rather, it
    //recreates the values based on the length of the data. This avoids
    //possibly reading past the end of an array.
    
    //Since the total number of points in a ClusterSet
    //is (M+1)*(M+2)/2, where M is the number of clusters -1, we can easily
    //verify that a valid number of points was passed.
    //Some versions of Windows SDK have problems with passing an integer
    //type to the sqrt function, so this explicit typecasting should take
    //care of the problem.
    M=(-3+static_cast<size_t>(sqrt(static_cast<double>(1+8*totalNumEls))))/2;        
    if((M+1)*(M+2)/2!=totalNumEls) {
        mexErrMsgTxt("The ClusterSets contain an inconsistent number of elements.");
    }
    
    //Otherwise, fill in the values for the cluster sizes and the ofset
    //array.
    CStdDev.numClust=M+1;
    SStdDev.numClust=M+1;
    
    theOffsetArray=new size_t[M+1];
    theClusterSizes=new size_t[M+1];
    theClusterSizes[0]=1;
    theOffsetArray[0]=0;
    for(i=1;i<=M;i++) {
       theOffsetArray[i]=theOffsetArray[i-1]+theClusterSizes[i-1];
       theClusterSizes[i]=i+1; 
    }

    CStdDev.totalNumEl=totalNumEls;
    SStdDev.totalNumEl=totalNumEls;
    CStdDev.offsetArray=theOffsetArray;
    SStdDev.offsetArray=theOffsetArray;
    CStdDev.clusterSizes=theClusterSizes;
    SStdDev.clusterSizes=theClusterSizes;

    //Get the other parameters.
    checkRealDoubleArray(prhs[2]);
    point=reinterpret_cast<double*>(mxGetData(prhs[2]));
    numPoints=mxGetN(prhs[2]);
    a=getDoubleFromMatlab(prhs[3]);
    c=getDoubleFromMatlab(prhs[4]);
    scalFactor=getDoubleFromMatlab(prhs[5]);
    
    //Allocate space for the return values
    sigma2MATLAB=mxCreateDoubleMatrix(numPoints, 1,mxREAL);
    sigma2=reinterpret_cast<double*>(mxGetData(sigma2MATLAB));
    
    if(nlhs>1) {
        mwSize dims[3];
        //A 3X3X numPoints array is needed for the covariance matrices.
        dims[0]=3;
        dims[1]=3;
        dims[2]=numPoints;
        
        SigmaMATLAB=mxCreateNumericArray(3,dims,mxDOUBLE_CLASS,mxREAL);
        Sigma=reinterpret_cast<double*>(mxGetData(SigmaMATLAB));
    } else {
        Sigma=NULL;
    }
    didOverflow=spherHarmonicCovCPP(sigma2,Sigma,CStdDev,SStdDev,point,numPoints,a,c,scalFactor);
            
    //Free the allocated space for the offet array and cluster sizes
    delete[] theOffsetArray;
    delete[] theClusterSizes;
            
    plhs[0]=sigma2MATLAB;
    
    if(nlhs>1) {
        plhs[1]=SigmaMATLAB;
        if(nlhs>2) {
            plhs[2]=boolMat2Matlab(&didOverflow,1,1);
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double TT1, TT2, dX, dY, *xVec;
    size_t numRow, numVec;
    mxArray *retMat;
    double *retData;
    double GCRS2CIRS[3][3];
    
    if(nrhs<3||nrhs>4){
        mexErrMsgTxt("Wrong number of inputs");
    }
    
    if(nlhs>2) {
        mexErrMsgTxt("Wrong number of outputs.");
    }
    
    checkRealDoubleArray(prhs[0]);
    
    numRow = mxGetM(prhs[0]);
    numVec = mxGetN(prhs[0]);
    
    if(!(numRow==3||numRow==6)) {
        mexErrMsgTxt("The input vector has a bad dimensionality.");
    }

    xVec=(double*)mxGetData(prhs[0]);
    TT1=getDoubleFromMatlab(prhs[1]);
    TT2=getDoubleFromMatlab(prhs[2]);
    
    //If some values from the function getEOP will be needed.
    if(nrhs<4||mxGetM(prhs[3])==0) {
        mxArray *retVals[2];
        double *dXdY;
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        int retVal;
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
        
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(2,retVals,2,JulUTCMATLAB,"getEOP");
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
        
        //%We do not need the polar motion coordinates.
        mxDestroyArray(retVals[0]);
        
        checkRealDoubleArray(retVals[1]);
        if(mxGetM(retVals[1])!=2||mxGetN(retVals[1])!=1) {
            mxDestroyArray(retVals[1]);
            mexErrMsgTxt("Error using the getEOP function.");
            return;
        }
        
        dXdY=(double*)mxGetData(retVals[1]);
        dX=dXdY[0];
        dY=dXdY[1];
        
        //Free the returned arrays.
        mxDestroyArray(retVals[1]);
    } else {//Get the celestial pole offsets
        size_t dim1, dim2;
        
        checkRealDoubleArray(prhs[4]);
        dim1 = mxGetM(prhs[4]);
        dim2 = mxGetN(prhs[4]);
        
        if((dim1==2&&dim2==1)||(dim1==1&&dim2==2)) {
            double *dXdY=(double*)mxGetData(prhs[4]);
        
            dX=dXdY[0];
            dY=dXdY[1];
        } else {
            mexErrMsgTxt("The celestial pole offsets have the wrong dimensionality.");
            return;
        }
    }
    
    {
    double x, y, s;
    double omega;
        
    //Get the X,Y coordinates of the Celestial Intermediate Pole (CIP) and
    //the Celestial Intermediate Origin (CIO) locator s, using the IAU 2006
    //precession and IAU 2000A nutation models.
    iauXys06a(TT1, TT2, &x, &y, &s);
    
    //Add the CIP offsets.
    x += dX;
    y += dY;
    
    //Get the GCRS-to-CIRS matrix
    iauC2ixys(x, y, s, GCRS2CIRS);
    }
    
    //Allocate space for the return vectors.
    retMat=mxCreateDoubleMatrix(numRow,numVec,mxREAL);
    retData=(double*)mxGetData(retMat);
    
    {
        size_t curVec;
        for(curVec=0;curVec<numVec;curVec++) {
            //Multiply the position vector with the rotation matrix.
            iauRxp(GCRS2CIRS, xVec+numRow*curVec, retData+numRow*curVec);
            
            //If a velocity vector was given.
            if(numRow>3) {
                double *velGCRS=xVec+numRow*curVec+3;//Velocity in GCRS
                double *retDataVel=retData+numRow*curVec+3;
                
                //Convert velocity from GCRS to CIRS.
                iauRxp(GCRS2CIRS, velGCRS, retDataVel);
            }
        }
    }
    plhs[0]=retMat;
    
    //If the rotation matrix is desired on the output.
    if(nlhs>1) {
        double *elPtr;
        size_t i,j;
        
        plhs[1]=mxCreateDoubleMatrix(3,3,mxREAL);
        elPtr=(double*)mxGetData(plhs[1]);
        
        for (i=0;i<3;i++) {
            for(j=0;j<3;j++) {
                elPtr[i+3*j]=GCRS2CIRS[i][j];
            }
        }
    }
}
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    double TT1, TT2, UT11,UT12, deltaT,GMST;
    int algToUse=2006;
    int retVal;
    
    if(nrhs<2||nrhs>4){
        mexErrMsgTxt("Wrong number of inputs.");
        return;
    }

    if(nlhs>1){
        mexErrMsgTxt("Wrong number of outputs.");
        return;
    }
    
    TT1=getDoubleFromMatlab(prhs[0]);
    TT2=getDoubleFromMatlab(prhs[1]);
    
    if(nrhs>2) {
        algToUse=getIntFromMatlab(prhs[2]);
    }
    
    if(nrhs>3) {
        deltaT=getDoubleFromMatlab(prhs[3]);
    } else {
        mxArray *retVals[4];
        mxArray *JulUTCMATLAB[2];
        double JulUTC[2];
        
        //Get the time in UTC to look up the parameters by going to TAI and
        //then UTC.
        retVal=iauTttai(TT1, TT2, &JulUTC[0], &JulUTC[1]);
        if(retVal!=0) {
            mexErrMsgTxt("An error occurred computing TAI.");
        }
        
        retVal=iauTaiutc(JulUTC[0], JulUTC[1], &JulUTC[0], &JulUTC[1]);
        switch(retVal){
            case 1:
                mexWarnMsgTxt("Dubious Date entered.");
                break;
            case -1:
                mexErrMsgTxt("Unacceptable date entered");
                break;
            default:
                break;
        }
 
        JulUTCMATLAB[0]=doubleMat2Matlab(&JulUTC[0],1,1);
        JulUTCMATLAB[1]=doubleMat2Matlab(&JulUTC[1],1,1);

        //Get the Earth orientation parameters for the given date.
        mexCallMATLAB(4,retVals,2,JulUTCMATLAB,"getEOP");
        //This is TT-UT1
        deltaT=getDoubleFromMatlab(retVals[3]);
        //Free the returned arrays.
        mxDestroyArray(retVals[0]);
        mxDestroyArray(retVals[1]);
        mxDestroyArray(retVals[2]);
        mxDestroyArray(retVals[3]);
        mxDestroyArray(JulUTCMATLAB[0]);
        mxDestroyArray(JulUTCMATLAB[1]);
    }
     
    //Get UT1
    retVal=iauTtut1(TT1, TT2, deltaT, &UT11, &UT12);
    if(retVal!=0) {
        mexErrMsgTxt("An error occurred computing UT1.");
    }
    
    //Get Greenwhich mean sidereal time in radians using the chosen
    //algorithm
    switch(algToUse) {
        case 1982:
            GMST=iauGmst82(UT11, UT12);
            break;
        case 2000:
            GMST=iauGmst00(UT11, UT12, TT1, TT2);
            break;
        case 2006:
            GMST=iauGmst06(UT11, UT12, TT1, TT2);
            break;
        default:
            mexErrMsgTxt("An invalid algorithm version was given.");
    }

    plhs[0]=doubleMat2Matlab(&GMST,1, 1);
}