////////////////////////////////////////////////////////////////////////
//		THIS FILE IS THE INTERFACE FILE BETWEEN MATLAB AND C          //
////////////////////////////////////////////////////////////////////////

// Authors:   Matt Ueckermann, Themis Sapsis, 
//           Pierre Lermusiaux, Pat Haley for MIT course 2.29

////////////////////////////////////
//  DECLARE STANDARD HEADER FILES //
////////////////////////////////////

#include "math.h"
#include "mex.h"
#include <stdlib.h>
#include <string.h>
#define MIN(a,b) ((a)>(b)?(b):(a))
#define MAX(a,b) ((a)<(b)?(b):(a))

int sign(float v)
{
    return((v<0)-(v>0));
}
/////////////////////////////
// DEFINE LIMITER FUNCTION //
/////////////////////////////
double TVD(double phi)
{
     //MC limiter
      return(MAX(0.0, MIN(MIN(0.5 * (1.0 + phi), 2.0), 2.0 * phi)));
     //minmod limiter     
//      return(((phi) > (0) ? MIN(phi,1) : 0.0));
     //superbee
//      return(MAX(MAX(0,MIN(1.0, 2.0 * phi)),MIN(2,phi)));
     //Upwind
//   return(0.0);
     // Lax Wendroff (NOT TVD)
//    return(1.0);
}

////////////////////////////
//  MASTER FUNCTION FILE  //
////////////////////////////


//////////////////////////////////////////
// MATLAB INTERFACE FUNCTION DEFINITION //
//////////////////////////////////////////

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) {
    // Declare input variables
    double dx, dy, dt, *ui, *vi, *uj, *vj;
    int Nx, Ny, *Nodeu, *Nodev, Nbcs, NbcsDu, NbcsDv;
    
    
    // Declare output variables
    double *Fu, *Fv;
    
    //Declare working variables
    int i, j;
    double fl, fr, fu, fd, theta, Uj, sumQ, diffQ;
    
    // Some minor input/output error checking
    if (!(nrhs==14)) {
        mexErrMsgTxt("Need 14 input arguments");
    }
    if (!(nlhs==2)) {
        mexErrMsgTxt("Need 2 outputs arguments");
    }
    
    
    // Get access to input data from MATLAB
    // Pointers are used for large array
    // Scalar are re-created in memory
    
    /********!!!! WARNING !!!************/
    // WARNING !!!!  note that C is expecting to be pointing to type int32 from
    // Matlab.  Therefore, for this code to work, the C argument must be
    // int32.  This is done in matlab by int32(C);
    // The function is then called like [Bnew Cnew] = axB(5,B,int32(C));
    // Use double(Cnew) if you want to convert it back (this might slow things).
    /********!!!! WARNING !!!************/
    //[Fu Fv] = UVadvect_DO_CDS(Nx, Ny, dx, dy, ui, vi, uj, vj, Nodeu, Nodev, idsu, idsv)
    Nx      =   (int)     mxGetScalar( prhs[0]  );
    Ny      =   (int)     mxGetScalar( prhs[1]  );
    dx      =   (double)  mxGetScalar( prhs[2]  );
    dy      =   (double)  mxGetScalar( prhs[3]  );
    dt      =   (double)  mxGetScalar( prhs[4]  );
    ui      =   (double*) mxGetPr(     prhs[5]  );
    vi      =   (double*) mxGetPr(     prhs[6]  );
    uj      =   (double*) mxGetPr(     prhs[7]  );
    vj      =   (double*) mxGetPr(     prhs[8]  );
    Nodeu   =   (int*)    mxGetPr(     prhs[9]  );
    Nodev   =   (int*)    mxGetPr(     prhs[10]  );
    Nbcs    =   (int)     mxGetScalar( prhs[11] );
    NbcsDu  =   (int)     mxGetScalar( prhs[12] );
    NbcsDv  =   (int)     mxGetScalar( prhs[13] );
    //     idsu    =   (int*)    mxGetPr(     prhs[10] );
    //     Nidsu   =             mxGetM (     prhs[10] );
    //     idsv    =   (int*)    mxGetPr(     prhs[11] );
    //     Nidsv   =             mxGetM (     prhs[11] );
    // Example of outputting text to MATLAB
    //     if (time ==0)
    //         mexPrintf("Welcome message for time %f\n",time);
    
    // These macros allow easy access to values of u and v at
    //             UU
    //              U
    //      LL   L  X  R  RR
    //              D
    //             DD
    //  with respect to the current cell
    
    //First define macros for U
    #define UM ui[Nodeu[j  + i * (Ny + 2)] - 1] 
    #define UUU ui[Nodeu[j - 2  + i * (Ny + 2)] - 1]          
    #define UU ui[Nodeu[j - 1  + i   *(Ny + 2)] - 1]  
    #define UD ui[Nodeu[j + 1 + i * (Ny + 2)] - 1]     
    #define UDD ui[Nodeu[j + 2 + i * (Ny + 2)] - 1]   
    #define ULL ui[Nodeu[j + (i - 2) * (Ny + 2)] - 1]
    #define UL ui[Nodeu[j + (i - 1) * (Ny + 2)] - 1]
    #define UR ui[Nodeu[j + (i + 1) * (Ny + 2)] - 1]
    #define URR ui[Nodeu[j + (i + 2) * (Ny + 2)] - 1]        
    //We will also need to access an averaged value of V at the cell 
    //interface
    #define VAVEU 0.5 * (vj[Nodev[j - 1 +(i + 1) * (Ny + 1)] - 1] + vj[Nodev[j - 1 + i * (Ny + 1)] - 1] )
    #define VAVED 0.5 * (vj[Nodev[j +(i + 1) * (Ny + 1)] - 1] + vj[Nodev[j + i * (Ny + 1)] - 1] )    
    #define UjL 0.5 * (uj[Nodeu[j + (i - 1) * (Ny + 2)] - 1] + uj[Nodeu[j + (i) * (Ny + 2)] - 1]) //\
               +0.5 * (fabs(uj[Nodeu[j + (i - 1) * (Ny + 2)] - 1]) - fabs(uj[Nodeu[j + (i) * (Ny + 2)] - 1]))
    #define UjR 0.5 * (uj[Nodeu[j + (i + 1) * (Ny + 2)] - 1] + uj[Nodeu[j + (i) * (Ny + 2)] - 1]) //\
               -0.5 * (fabs(uj[Nodeu[j + (i + 1) * (Ny + 2)] - 1]) - fabs(uj[Nodeu[j + (i) * (Ny + 2)] - 1]))
  
   
            
    //Now Define macros for V
    #define VM vi[Nodev[j  + i * (Ny + 1)] - 1] 
    #define VUU vi[Nodev[j - 2  + i * (Ny + 1)] - 1]          
    #define VU vi[Nodev[j - 1  + i   *(Ny + 1)] - 1]  
    #define VD vi[Nodev[j + 1 + i * (Ny + 1)] - 1]     
    #define VDD vi[Nodev[j + 2 + i * (Ny + 1)] - 1]   
    #define VLL vi[Nodev[j + (i - 2) * (Ny + 1)] - 1]
    #define VL vi[Nodev[j + (i - 1) * (Ny + 1)] - 1]
    #define VR vi[Nodev[j + (i + 1) * (Ny + 1)] - 1]
    #define VRR vi[Nodev[j + (i + 2) * (Ny + 1)] - 1]        
    //We will also need to access an averaged value of V at the cell 
    //interface
    #define UAVEL 0.5 * ( uj[Nodeu[j + 1 +(i - 1) * (Ny + 2)] -1 ] + uj[Nodeu[j + (i - 1) * (Ny + 2)] - 1] )
    #define UAVER 0.5 * ( uj[Nodeu[j + 1 + i * (Ny + 2)   ] - 1] + uj[Nodeu[j  + i * (Ny + 2)] - 1] )
    #define VjD 0.5 * (vj[Nodev[j + i  * (Ny + 1)] - 1] + vj[Nodev[j + 1 + i * (Ny + 1)] - 1]) //\
               -0.5 * (fabs(vj[Nodev[j + i  * (Ny + 1)] - 1]) - fabs(vj[Nodev[j + 1 + i * (Ny + 1)] - 1]))
    #define VjU 0.5 * (vj[Nodev[j + i  * (Ny + 1)] - 1] + vj[Nodev[j - 1 + i * (Ny + 1)] - 1]) //\
               +0.5 * (fabs(vj[Nodev[j + i  * (Ny + 1)] - 1]) - fabs(vj[Nodev[j - 1 + i * (Ny + 1)] - 1]))  
    
    // ALLOCATE AND POINT TO OUTPUTS
    plhs[0] =   mxCreateDoubleMatrix((Nx-1)* Ny   , 1, mxREAL);
    plhs[1] =   mxCreateDoubleMatrix( Nx   *(Ny-1), 1, mxREAL);
    Fu      =   (double*)mxGetPr(plhs[0]);
    Fv      =   (double*)mxGetPr(plhs[1]);
    
    for(i=1;i<Nx;i++) {
        for(j=1;j<Ny+1;j++) {
            if (Nodeu[j  +(i)*(Ny+2)]<=Nbcs) //If this is a boundary node, don't do any work
            {
              Fu[j-1+(i-1)*Ny] = 0.0;  
            }
            else //do work
            {
            //U advection, quadratic upwind difference scheme
            //mexPrintf("%d, %f\n",Nodeu[j   +(i-1)*(Ny+2)]-1,dx );
            if(Nodeu[j  +(i-1)*(Ny+2)]>Nbcs) {
                //West face                
                sumQ = UM + UL;
                diffQ = UM - UL;
                Uj = UjL;
                theta = ((Uj + fabs(Uj)) / 2.0 * (UL - ULL) \
                            + (Uj - fabs(Uj)) / 2.0 * (UR - UM)) \
                            / (diffQ) / Uj;
            }
            else //treat boundary condition
            {
                if (Nodeu[j  +(i-1)*(Ny+2)]<=NbcsDu) {
                    //West face
                    sumQ = UM + UL;
                    diffQ = UM - UL;
                    Uj = UjL;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (diffQ) \
                            + (Uj - fabs(Uj)) / 2.0 * (UR - UM)) \
                            / (diffQ) / Uj;
                }
                else {
                    sumQ = 2.0 * UM + UL;
                    diffQ = UM - (UM + UL);
                    Uj = 2.0 * UjL;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (diffQ) \
                            + (Uj - fabs(Uj)) / 2.0 * (UR - UM)) \
                            / (diffQ) / Uj;
                }
            }
            //Treat additional boundary problems. The QUICk scheme won't
            // work if neumann boundaries are at i-2 or i+1
            if (i-2>=0) { //This is to avoid segfaults
                if(Nodeu[j+(i-2)*(Ny+2)]<=Nbcs && Nodeu[j+(i-2)*(Ny+2)]>NbcsDu) {
                    //if the most west boundary is Neumann use:
                    theta = ((Uj + fabs(Uj)) / 2.0 * (UL - (ULL + UL)) \
                            + (Uj - fabs(Uj)) / 2.0 * (UR - UM)) \
                            / (diffQ) / Uj;
                }
            }
            if(Nodeu[j+(i+1)*(Ny+2)]<=Nbcs && Nodeu[j+(i+1)*(Ny+2)]>NbcsDu) {
                //if the most east boundary is Neumann use:
                theta = ((Uj + fabs(Uj)) / 2.0 * (UL - ULL) \
                        + (Uj - fabs(Uj)) / 2.0 * ((UM + UR) - UM)) \
                        / (diffQ) / Uj;
            }
            fl = 0.5 * Uj * (sumQ) \
                    + 0.5 * fabs(Uj) * (-1.0 + (1.0 - fabs(Uj * dt / dx)) * TVD(theta)) \
                    * (diffQ);
            
            
            if (Nodeu[j  +(i+1)*(Ny+2)]>Nbcs) {
                //East face
                sumQ = UR + UM;
                diffQ = UR - UM;
                Uj = UjR;
                theta = ((Uj + fabs(Uj)) / 2.0 * (UM - UL) \
                        + (Uj - fabs(Uj)) / 2.0 * (URR - UR)) \
                        / (diffQ) / Uj;
            }
            else //treat boundary condition
            {
                if (Nodeu[j  +(i+1)*(Ny+2)]<=NbcsDu) {
                    //East face
                    sumQ = UR + UM;
                    diffQ = UR - UM;
                    Uj = UjR;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (UM - UL) \
                            + (Uj - fabs(Uj)) / 2.0 * (diffQ)) \
                            / (diffQ) / Uj;
                }
                else {
                    sumQ = UR + 2.0 * UM;
                    diffQ = (UM + UR) - UM;
                    Uj = 2.0 * UjR;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (UM - UL) \
                            + (Uj - fabs(Uj)) / 2.0 * (diffQ)) \
                            / (diffQ) / Uj;
                }
            }
            //Treat additional boundary problems. The QUICk scheme won't
            // work if neumann boundaries are at i-2 or i+1
            if (i + 2 <= Nx) { //This is to avoid segfaults
                if(Nodeu[j+(i+2)*(Ny+2)]<=Nbcs && Nodeu[j+(i+2)*(Ny+2)]>NbcsDu) {
                    //if the most east boundary is Neumann use CDS
                    theta = ((Uj + fabs(Uj)) / 2.0 * (UM - UL) \
                            + (Uj - fabs(Uj)) / 2.0 * ((UR + URR) - UR)) \
                            / (diffQ) / Uj;
                }
            }
            if(Nodeu[j+(i-1)*(Ny+2)]<=Nbcs && Nodeu[j+(i-1)*(Ny+2)]>NbcsDu) {
                //if the most west boundary is Neumann use CDS
                theta = ((Uj + fabs(Uj)) / 2.0 * (UM - (UM + UL)) \
                        + (Uj - fabs(Uj)) / 2.0 * (URR - UR)) \
                        / (diffQ) / Uj;
            }
            fr = 0.5 * Uj * (sumQ) \
                    + 0.5 * fabs(Uj) * (-1.0 + (1.0 - fabs(Uj * dt / dx)) * TVD(theta)) \
                    * (diffQ);
            
            if (Nodeu[j+1+ i*(Ny+2)]>Nbcs) {
                //South Face
                sumQ = UM + UD;
                diffQ = UM - UD;
                Uj = VAVED;
                theta = ((Uj + fabs(Uj)) / 2.0 * (UD - UDD) \
                        + (Uj - fabs(Uj)) / 2.0 * (UU - UM)) \
                        / (diffQ) / Uj;                
            }
            else { //treat boundaries
                if (Nodev[j   +(i+1)*(Ny+1)]<=NbcsDv || Nodev[j   +(i+1)*(Ny+1)]>Nbcs) { //Dirichlet on v
                    Uj = VAVED;
                }
                else {
                    Uj = 0.5*( vj[Nodev[j  +(i+1)*(Ny+1)]-1] + vj[Nodev[j-1 +(i+1)*(Ny+1)]-1] \
                            +  vj[Nodev[j  + i*   (Ny+1)]-1] + vj[Nodev[j-1+ i*   (Ny+1)]-1] );
                }
                if (Nodeu[j+1+(i)*(Ny+2)]<=NbcsDu) { //Dirichlet on u
                    sumQ = UM + UD;
                    diffQ = UM - UD;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (diffQ) \
                            + (Uj - fabs(Uj)) / 2.0 * (UU - UM)) \
                            / (diffQ) / Uj;
                }
                else { //Neumann on u
                    sumQ = 2.0 * UM + UD;
                    diffQ = UM - (UM + UD);
                    theta = ((Uj + fabs(Uj)) / 2.0 * (diffQ) \
                            + (Uj - fabs(Uj)) / 2.0 * (UU - UM)) \
                            / (diffQ) / Uj;
                }                               
            }
            //Treat additional boundary problems. The QUICk scheme won't
            // work if neumann boundaries are at i-2 or i+1
            if (j+2<=Ny+1) { //This is to avoid segfaults
                if(Nodeu[j+2+i*(Ny+2)]<=Nbcs && Nodeu[j+2+i*(Ny+2)]>NbcsDu) {
                    //if the most north boundary is Neumann use CDS
                    theta = ((Uj + fabs(Uj)) / 2.0 * (UD - (UD + UDD)) \
                        + (Uj - fabs(Uj)) / 2.0 * (UU - UM)) \
                        / (diffQ) / Uj; 
                }
            }
            if(Nodeu[j-1+i*(Ny+2)]<=Nbcs && Nodeu[j-1+i*(Ny+2)]>NbcsDu) {
                //if the most south boundary is Neumann use CDS
               theta = ((Uj + fabs(Uj)) / 2.0 * (UD - UDD) \
                        + (Uj - fabs(Uj)) / 2.0 * ((UU + UM) - UM)) \
                        / (diffQ) / Uj; 
            }
            fd = 0.5 * Uj * (sumQ) \
                    + 0.5 * fabs(Uj) * (-1.0 + (1.0 - fabs(Uj * dt / dy)) * TVD(theta)) \
                    * (diffQ);
            
            //North Face
            if (Nodeu[j-1+ i*(Ny+2)]>Nbcs) {
                sumQ = UU + UM;
                diffQ = UU - UM;
                Uj = VAVEU;
                theta = ((Uj + fabs(Uj)) / 2.0 * (UM - UD) \
                        + (Uj - fabs(Uj)) / 2.0 * (UUU - UU)) \
                        / (diffQ) / Uj; 
            }
            else { //treat boundaries
                if (Nodev[j-1 +(i+1)*(Ny+1)]<=NbcsDv || Nodev[j-1 +(i+1)*(Ny+1)]>Nbcs) { //Dirichlet on v
                    Uj = VAVEU;
                }
                else { //Neuman on v
                    Uj = 0.5*( vj[Nodev[j  +(i+1)*(Ny+1)]-1] + vj[Nodev[j-1 +(i+1)*(Ny+1)]-1] \
                            +  vj[Nodev[j  + i*   (Ny+1)]-1] + vj[Nodev[j-1 + i*   (Ny+1)]-1] );
                }
                if (Nodeu[j-1+(i)*(Ny+2)]<=NbcsDu) { //Dirichlet on u
                    sumQ = UU + UM;
                    diffQ = UU - UM;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (UM - UD) \
                            + (Uj - fabs(Uj)) / 2.0 * (diffQ)) \
                            / (diffQ) / Uj;
                }
                else { //Neuman on u
                    sumQ = 2.0 * UM + UU;
                    diffQ = UM - (UM + UU);
                    theta = ((Uj + fabs(Uj)) / 2.0 * (UM - UD) \
                            + (Uj - fabs(Uj)) / 2.0 * (diffQ)) \
                            / (diffQ) / Uj;
                }
            }
            //Treat additional boundary problems. The QUICk scheme won't
            // work if neumann boundaries are at i-2 or i+1
            if (j-2>=0) { //This is to avoid segfaults
                if(Nodeu[j-2+i*(Ny+2)]<=Nbcs && Nodeu[j-2+i*(Ny+2)]>NbcsDu) {
                    //if the most north boundary is Neumann use CDS
                    theta = ((Uj + fabs(Uj)) / 2.0 * (UM - UD) \
                        + (Uj - fabs(Uj)) / 2.0 * ((UUU + UU) - UU)) \
                        / (diffQ) / Uj;
                }
            }
            if(Nodeu[j+1+i*(Ny+2)]<=Nbcs && Nodeu[j+1+i*(Ny+2)]>NbcsDu) {
                //if the most south boundary is Neumann use CDS
                theta = ((Uj + fabs(Uj)) / 2.0 * (UM - (UD + UM)) \
                        + (Uj - fabs(Uj)) / 2.0 * (UUU - UU)) \
                        / (diffQ) / Uj;
            }
            fu = 0.5 * Uj * (sumQ) \
                    + 0.5 * fabs(Uj) * (-1.0 + (1.0 - fabs(Uj * dt / dy)) * TVD(theta)) \
                    * (diffQ);
            
            //Calculate Total flux change for this cell
            Fu[j-1+(i-1)*Ny] = (fl - fr) / dx + (fd - fu) / dy;
            }            
        }
    }
    
    for(i=1;i<Nx+1;i++) {
        for(j=1;j<Ny;j++) {
            if (Nodev[j  +(i)*(Ny+1)]<=Nbcs) //If boundary node don't do work
            {
               Fv[j-1+(i-1)*(Ny-1)] = 0.0; 
            }
            else //do work
            {
            //V advection, QUICK scheme
            //mexPrintf("%d, %f\n",Nodeu[j   +(i-1)*(Ny+2)]-1,dx );
            if(Nodev[j  +(i-1)*(Ny+1)]>Nbcs) {
                //West face
                sumQ = VM + VL;
                diffQ = VM - VL;
                Uj = UAVEL;
                theta = ((Uj + fabs(Uj)) / 2.0 * (VL - VLL) \
                        + (Uj - fabs(Uj)) / 2.0 * (VR - VM)) \
                        / (diffQ) / Uj;
            }
            else //treat boundary condition
            {
                if (Nodeu[j+1 +(i-1)*(Ny+2)]<=NbcsDu || Nodeu[j+1 +(i-1)*(Ny+2)]>Nbcs) { //dirichlet on u
                    Uj = UAVEL;
                }
                else {
                    Uj = 0.5*( uj[Nodeu[j+1 +(i-1)*(Ny+2)]-1]+uj[Nodeu[j+1 +(i)*(Ny+2)]-1]\
                            + uj[Nodeu[j +  (i-1)*(Ny+2)]-1]+uj[Nodeu[j   +(i)*(Ny+2)]-1] );
                }
                //West face
                if (Nodev[j  +(i-1)*(Ny+1)]-1<=NbcsDv) { //dirichlet on v
                    sumQ = VM + VL;
                    diffQ = VM - VL;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (diffQ) \
                            + (Uj - fabs(Uj)) / 2.0 * (VR - VM)) \
                            / (diffQ) / Uj;
                }
                else { //Neuman on v
                    sumQ = 2.0 * VM + VL;
                    diffQ = VM - (VL + VM);
                    theta = ((Uj + fabs(Uj)) / 2.0 * (diffQ) \
                            + (Uj - fabs(Uj)) / 2.0 * (VR - VM)) \
                            / (diffQ) / Uj;
                }
            }
            //Treat additional boundary problems. The QUICk scheme won't
            // work if neumann boundaries are at i-2 or i+1
            if (i-2>=0) { //This is to avoid segfaults
                if(Nodev[j+(i-2)*(Ny+1)]<=Nbcs && Nodev[j+(i-2)*(Ny+1)]>NbcsDv) {
                    //if the most west boundary is Neumann use CDS
                    theta = ((Uj + fabs(Uj)) / 2.0 * (VL - (VL + VLL)) \
                            + (Uj - fabs(Uj)) / 2.0 * (VR - VM)) \
                            / (diffQ) / Uj;
                }
            }
            if(Nodev[j+(i+1)*(Ny+1)]<=Nbcs && Nodev[j+(i+1)*(Ny+1)]>NbcsDv) {
                //if the most east boundary is Neumann use CDS
                theta = ((Uj + fabs(Uj)) / 2.0 * (VL - VLL) \
                        + (Uj - fabs(Uj)) / 2.0 * ((VR + VM) - VM)) \
                        / (diffQ) / Uj;
            }
            fl = 0.5 * Uj * (sumQ) \
                    + 0.5 * fabs(Uj) * (-1.0 + (1.0 - fabs(Uj * dt / dx)) * TVD(theta)) \
                    * (diffQ);
            
            if (Nodev[j  +(i+1)*(Ny+1)]>Nbcs) {
                //East face
                sumQ = VR + VM;
                diffQ = VR - VM;
                Uj = UAVER;
                theta = ((Uj + fabs(Uj)) / 2.0 * (VM - VL) \
                        + (Uj - fabs(Uj)) / 2.0 * (VRR - VR)) \
                        / (diffQ) / Uj;
            }
            else //treat boundary condition
            {
                //East face
                if (Nodeu[j+1 +(i)*(Ny+2)]<=NbcsDu || Nodeu[j+1 +(i)*(Ny+2)]>Nbcs) { //dirichlet on u
                    Uj = UAVER;
                }
                else { //neuman on u
                    Uj = 0.5*( uj[Nodeu[j+1 +(i-1)*(Ny+2)]-1]+uj[Nodeu[j+1 +(i)*(Ny+2)]-1]\
                            + uj[Nodeu[j +  (i-1)*(Ny+2)]-1]+uj[Nodeu[j   +(i)*(Ny+2)]-1] );
                }
                if (Nodev[j  +(i+1)*(Ny+1)]-1<=NbcsDv) {//Dirichlet on v
                    sumQ = VR + VM;
                    diffQ = VR - VM;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (VM - VL) \
                            + (Uj - fabs(Uj)) / 2.0 * (diffQ)) \
                            / (diffQ) / Uj;
                }
                else { //Neumann on v
                    sumQ = VR + 2.0 * VM;
                    diffQ = (VM + VR) - VM;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (VM - VL) \
                            + (Uj - fabs(Uj)) / 2.0 * (diffQ)) \
                            / (diffQ) / Uj;
                }                
            }
            //Treat additional boundary problems. The QUICk scheme won't
            // work if neumann boundaries are at i-2 or i+1
            if (i+2<=Nx+1) { //This is to avoid segfaults
                if(Nodev[j+(i+2)*(Ny+1)]<=Nbcs && Nodev[j+(i+2)*(Ny+1)]>NbcsDv) {
                    //if the most east boundary is Neumann use CDS
                    theta = ((Uj + fabs(Uj)) / 2.0 * (VM - VL) \
                        + (Uj - fabs(Uj)) / 2.0 * ((VRR + VR) - VR)) \
                        / (diffQ) / Uj;
                }
            }
            if(Nodev[j+(i-1)*(Ny+1)]<=Nbcs && Nodev[j+(i-1)*(Ny+1)]>NbcsDv) {
                //if the most west boundary is Neumann use CDS
                theta = ((Uj + fabs(Uj)) / 2.0 * (VM - (VL + VM)) \
                        + (Uj - fabs(Uj)) / 2.0 * (VRR - VR)) \
                        / (diffQ) / Uj;
            }
            fr = 0.5 * Uj * (sumQ) \
                    + 0.5 * fabs(Uj) * (-1.0 + (1.0 - fabs(Uj * dt / dx)) * TVD(theta)) \
                    * (diffQ);
            
            
            if (Nodev[j+1+ i*(Ny+1)]>Nbcs) {
                //South Face
                sumQ = VM + VD;
                diffQ = VM - VD;
                Uj = VjD;
                theta = ((Uj + fabs(Uj)) / 2.0 * (VD - VDD) \
                        + (Uj - fabs(Uj)) / 2.0 * (VU - VM)) \
                        / (diffQ) / Uj;
            }
            else {
                if (Nodev[j+1+(i)*(Ny+1)]-1<=NbcsDv) {
                    sumQ = VM + VD;
                    diffQ = VM - VD;
                    Uj = VjD;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (diffQ) \
                            + (Uj - fabs(Uj)) / 2.0 * (VU - VM)) \
                            / (diffQ) / Uj;
                }
                else {
                    sumQ = 2.0 * VM + VD;
                    diffQ = VM - (VM + VD);
                    Uj = 2.0 * VjD;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (diffQ) \
                            + (Uj - fabs(Uj)) / 2.0 * (VU - VM)) \
                            / (diffQ) / Uj;
                }
            }
            //Treat additional boundary problems. The QUICk scheme won't
            // work if neumann boundaries are at i-2 or i+1
            if (j+2<=Ny) { //This is to avoid segfaults
                if(Nodev[j+2+i*(Ny+1)]<=Nbcs && Nodev[j+2+i*(Ny+1)]>NbcsDv) {
                    //if the most south boundary is Neumann use CDS
                    theta = ((Uj + fabs(Uj)) / 2.0 * (VD - ( VD + VDD)) \
                            + (Uj - fabs(Uj)) / 2.0 * (VU - VM)) \
                            / (diffQ) / Uj;
                }
            }
            if(Nodev[j-1+i*(Ny+1)]<=Nbcs && Nodev[j-1+i*(Ny+1)]>NbcsDv) {
                //if the most north boundary is Neumann use CDS
                theta = ((Uj + fabs(Uj)) / 2.0 * (VD - VDD) \
                        + (Uj - fabs(Uj)) / 2.0 * ((VU + VM) - VM)) \
                        / (diffQ) / Uj;
            }
            fd = 0.5 * Uj * (sumQ) \
                    + 0.5 * fabs(Uj) * (-1.0 + (1.0 - fabs(Uj * dt / dy)) * TVD(theta)) \
                    * (diffQ);
            

            //North Face
            if (Nodev[j-1+ i*(Ny+1)]>Nbcs) {
                sumQ = VU + VM;
                diffQ = VU - VM;
                Uj = VjU;
                theta = ((Uj + fabs(Uj)) / 2.0 * (VM - VD) \
                        + (Uj - fabs(Uj)) / 2.0 * (VUU - VU)) \
                        / (diffQ) / Uj;
            }
            else {
                if (Nodev[j-1+(i)*(Ny+1)]-1<=NbcsDv) {
                    sumQ = VU + VM;
                    diffQ = VU - VM;
                    Uj = VjU;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (VM - VD) \
                            + (Uj - fabs(Uj)) / 2.0 * (diffQ)) \
                            / (diffQ) / Uj;
                }
                else {
                    sumQ = VU + 2.0 * VM;
                    diffQ = (VU + VM) - VM;
                    Uj = 2.0 * VjU;
                    theta = ((Uj + fabs(Uj)) / 2.0 * (VM - VD) \
                            + (Uj - fabs(Uj)) / 2.0 * (diffQ)) \
                            / (diffQ) / Uj;
                }
            }
             //Treat additional boundary problems. The QUICk scheme won't
            // work if neumann boundaries are at i-2 or i+1
            if (j-2>=0) { //This is to avoid segfaults
                if(Nodev[j-2+i*(Ny+1)]<=Nbcs && Nodev[j-2+i*(Ny+1)]>NbcsDv) {
                    //if the most north boundary is Neumann use CDS
                    theta = ((Uj + fabs(Uj)) / 2.0 * (VM - VD) \
                            + (Uj - fabs(Uj)) / 2.0 * ((VUU + VU) - VU)) \
                            / (diffQ) / Uj;
                }
            }
            if(Nodev[j+1+i*(Ny+1)]<=Nbcs && Nodev[j+1+i*(Ny+1)]>NbcsDv) {
                //if the most south boundary is Neumann use CDS
                theta = ((Uj + fabs(Uj)) / 2.0 * (VM - (VM + VD)) \
                        + (Uj - fabs(Uj)) / 2.0 * (VUU - VU)) \
                        / (diffQ) / Uj;
            }

            fu = 0.5 * Uj * (sumQ) \
                    + 0.5 * fabs(Uj) * (-1.0 + (1.0 - fabs(Uj * dt / dy)) * TVD(theta)) \
                    * (diffQ);
            
            //Calculate total flux for this cell
            Fv[j-1+(i-1)*(Ny-1)] = (fl - fr) / dx + (fd - fu) / dy;
            }
        }
    }
}