////////////////////////////////////////////////////////////////////////
//		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>

int sign(float v)
{
    return((v<0)-(v>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, *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 fw, fe, fn, fs, Uiws, Uien, Ujws, Ujen, Vj, Uj;
    
    // Some minor input/output error checking
    if (!(nrhs==13)) {
        mexErrMsgTxt("Need 13 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]  );
    ui      =   (double*) mxGetPr(     prhs[4]  );
    vi      =   (double*) mxGetPr(     prhs[5]  );
    uj      =   (double*) mxGetPr(     prhs[6]  );
    vj      =   (double*) mxGetPr(     prhs[7]  );
    Nodeu   =   (int*)    mxGetPr(     prhs[8]  );
    Nodev   =   (int*)    mxGetPr(     prhs[9]  );
    Nbcs    =   (int)     mxGetScalar( prhs[10] );
    NbcsDu  =   (int)     mxGetScalar( prhs[11] );
    NbcsDv  =   (int)     mxGetScalar( prhs[12] );
    //     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);
    
    
    // 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
                Uiws = 3.0/8.0*ui[Nodeu[j  + i   *(Ny+2)]-1] +\
                        6.0/8.0*ui[Nodeu[j  +(i-1)*(Ny+2)]-1] -\
                        1.0/8.0*ui[Nodeu[j  +(i-2)*(Ny+2)]-1];
                Uien = 3.0/8.0*ui[Nodeu[j  +(i-1)*(Ny+2)]-1] +\
                        6.0/8.0*ui[Nodeu[j  +(i  )*(Ny+2)]-1] -\
                        1.0/8.0*ui[Nodeu[j  +(i+1)*(Ny+2)]-1];
                Ujws = 3.0/8.0*uj[Nodeu[j  + i   *(Ny+2)]-1] +\
                        6.0/8.0*uj[Nodeu[j  +(i-1)*(Ny+2)]-1] -\
                        1.0/8.0*uj[Nodeu[j  +(i-2)*(Ny+2)]-1];
                Ujen = 3.0/8.0*uj[Nodeu[j  +(i-1)*(Ny+2)]-1] +\
                        6.0/8.0*uj[Nodeu[j  +(i  )*(Ny+2)]-1] -\
                        1.0/8.0*uj[Nodeu[j  +(i+1)*(Ny+2)]-1];
            }
            else //treat boundary condition
            {
                if (Nodeu[j  +(i-1)*(Ny+2)]<=NbcsDu) {
                    //West face
                    Uiws = 0.5*(ui[Nodeu[j  +(i-1)*(Ny+2)]-1]+ui[Nodeu[j  +(i  )*(Ny+2)]-1]);
                    Uien = Uiws;
                    Ujws = 0.5*(uj[Nodeu[j  +(i-1)*(Ny+2)]-1]+uj[Nodeu[j  +(i  )*(Ny+2)]-1]);
                    Ujen = Ujws;
                }
                else {
                    Uiws= (0.5*ui[Nodeu[j  +(i-1)*(Ny+2)]-1]+ui[Nodeu[j  +(i)*(Ny+2)]-1]);
                    Uien = Uiws;
                    Ujws= (0.5*uj[Nodeu[j  +(i-1)*(Ny+2)]-1]+uj[Nodeu[j  +(i)*(Ny+2)]-1]);
                    Ujen = Ujws;
                }
            }
            //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 CDS
                    Uiws = 0.5*(ui[Nodeu[j  +(i-1)*(Ny+2)]-1]+ui[Nodeu[j  +(i  )*(Ny+2)]-1]);
                    Ujws = 0.5*(uj[Nodeu[j  +(i-1)*(Ny+2)]-1]+uj[Nodeu[j  +(i  )*(Ny+2)]-1]);
                }
            }
            if(Nodeu[j+(i+1)*(Ny+2)]<=Nbcs && Nodeu[j+(i+1)*(Ny+2)]>NbcsDu) {
                //if the most east boundary is Neumann use CDS
                Uien = 0.5*(ui[Nodeu[j  +(i-1)*(Ny+2)]-1]+ui[Nodeu[j  +(i  )*(Ny+2)]-1]);
                Ujen = 0.5*(uj[Nodeu[j  +(i-1)*(Ny+2)]-1]+uj[Nodeu[j  +(i  )*(Ny+2)]-1]);
            }
            //Do some minor slope limiting
            if (i-2>=0) { 
                if (sign(uj[Nodeu[j  +(i-1)*(Ny+2)]-1]) != sign(uj[Nodeu[j  +(i-2)*(Ny+2)]-1]))
                {
                    Uiws  = ui[Nodeu[j  +(i-1)*(Ny+2)]-1];
                    Ujws  = uj[Nodeu[j  +(i-1)*(Ny+2)]-1];
                }                
            }
            if (sign(uj[Nodeu[j  +(i+1)*(Ny+2)]-1]) != sign(uj[Nodeu[j  +(i)*(Ny+2)]-1])) {
                Uien  = ui[Nodeu[j  +(i)*(Ny+2)]-1];
                Ujen  = uj[Nodeu[j  +(i)*(Ny+2)]-1];
            }
            fw = (0.5/dx)*(Uiws*(Ujws+fabs(Ujws)) + Uien*(Ujen-fabs(Ujen)) );
            
            if (Nodeu[j  +(i+1)*(Ny+2)]>Nbcs) {
                //East face
                Uiws = 3.0/8.0*ui[Nodeu[j  +(i+1)*(Ny+2)]-1] +\
                        6.0/8.0*ui[Nodeu[j  +(i  )*(Ny+2)]-1] -\
                        1.0/8.0*ui[Nodeu[j  +(i-1)*(Ny+2)]-1];
                Uien = 3.0/8.0*ui[Nodeu[j  +(i  )*(Ny+2)]-1] +\
                        6.0/8.0*ui[Nodeu[j  +(i+1)*(Ny+2)]-1] -\
                        1.0/8.0*ui[Nodeu[j  +(i+2)*(Ny+2)]-1];
                Ujws = 3.0/8.0*uj[Nodeu[j  +(i+1)*(Ny+2)]-1] +\
                        6.0/8.0*uj[Nodeu[j  +(i  )*(Ny+2)]-1] -\
                        1.0/8.0*uj[Nodeu[j  +(i-1)*(Ny+2)]-1];
                Ujen = 3.0/8.0*uj[Nodeu[j  +(i  )*(Ny+2)]-1] +\
                        6.0/8.0*uj[Nodeu[j  +(i+1)*(Ny+2)]-1] -\
                        1.0/8.0*uj[Nodeu[j  +(i+2)*(Ny+2)]-1];
            }
            else //treat boundary condition
            {
                if (Nodeu[j  +(i+1)*(Ny+2)]<=NbcsDu) {
                    //mexPrintf("Dirichlet %d,%d, %f\n",Nodeu[j+(i+1)*(Ny+2)]-1,NbcsDu,uj[Nodeu[j   +(i+1)*(Ny+2)]-1] );
                    //East face
                    Uiws = 0.5*(ui[Nodeu[j   +(i+1)*(Ny+2)]-1] + ui[Nodeu[j  +i*(Ny+2)]-1]);
                    Uien = Uiws;
                    Ujws = 0.5*(uj[Nodeu[j   +(i+1)*(Ny+2)]-1] + uj[Nodeu[j  +i*(Ny+2)]-1]);
                    Ujen = Ujws;
                }
                else {
                    Uiws = (0.5*ui[Nodeu[j   +(i+1)*(Ny+2)]-1] + ui[Nodeu[j  +i*(Ny+2)]-1]);
                    Uien = Uiws;
                    Ujws = (0.5*uj[Nodeu[j   +(i+1)*(Ny+2)]-1] + uj[Nodeu[j  +i*(Ny+2)]-1]);
                    Ujen = Ujws;
                    //mexPrintf("Neumann %d,%d, %f\n",Nodeu[j+(i+1)*(Ny+2)]-1,NbcsDu,uj[Nodeu[j   +(i+1)*(Ny+2)]-1] );
                }
            }
            //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
                    Uien = 0.5*(ui[Nodeu[j   +(i+1)*(Ny+2)]-1] + ui[Nodeu[j  +i*(Ny+2)]-1]);
                    Ujen = 0.5*(uj[Nodeu[j   +(i+1)*(Ny+2)]-1] + uj[Nodeu[j  +i*(Ny+2)]-1]);
                }
            }
            if(Nodeu[j+(i-1)*(Ny+2)]<=Nbcs && Nodeu[j+(i-1)*(Ny+2)]>NbcsDu) {
                //if the most west boundary is Neumann use CDS
                Uiws = 0.5*(ui[Nodeu[j   +(i+1)*(Ny+2)]-1] + ui[Nodeu[j  +i*(Ny+2)]-1]);
                Ujws = 0.5*(uj[Nodeu[j   +(i+1)*(Ny+2)]-1] + uj[Nodeu[j  +i*(Ny+2)]-1]);
            }
            
            //Do some minor slope limiting
            if (sign(uj[Nodeu[j  +(i-1)*(Ny+2)]-1]) != sign(uj[Nodeu[j  +(i)*(Ny+2)]-1])) {
                Uiws  = ui[Nodeu[j  +(i)*(Ny+2)]-1];
                Ujws  = uj[Nodeu[j  +(i)*(Ny+2)]-1];
            }
            if (i + 2 <= Nx) {
                if (sign(uj[Nodeu[j  +(i+1)*(Ny+2)]-1]) != sign(uj[Nodeu[j+(i+2)*(Ny+2)]-1])) {
                    Uien  = ui[Nodeu[j  +(i + 1)*(Ny+2)]-1];
                    Ujen  = uj[Nodeu[j  +(i + 1)*(Ny+2)]-1];
                }
            }
            fe = (0.5/dx)*(Uiws*(Ujws+fabs(Ujws)) + Uien*(Ujen-fabs(Ujen)) );
            
            if (Nodeu[j+1+ i*(Ny+2)]>Nbcs) {
                //South Face
                Uiws = 3.0/8.0*ui[Nodeu[j  + i*(Ny+2)]-1] +\
                        6.0/8.0*ui[Nodeu[j+1+ i*(Ny+2)]-1] -\
                        1.0/8.0*ui[Nodeu[j+2+ i*(Ny+2)]-1];
                Uien = 3.0/8.0*ui[Nodeu[j+1+ i*(Ny+2)]-1] +\
                        6.0/8.0*ui[Nodeu[j  + i*(Ny+2)]-1] -\
                        1.0/8.0*ui[Nodeu[j-1+ i*(Ny+2)]-1];
                Vj = 0.5*( vj[Nodev[j   +(i+1)*(Ny+1)]-1] +  vj[Nodev[j  +i*(Ny+1)]-1] );
            }
            else { //treat boundaries
                if (Nodeu[j+1+(i)*(Ny+2)]<=NbcsDu) { //Dirichlet on u
                    Uiws = 0.5*(ui[Nodeu[j+1+ i*(Ny+2)]-1]+ui[Nodeu[j  + i*(Ny+2)]-1]);
                    Uien = Uiws;
                }
                else { //Neumann on u
                    Uiws = (0.5*ui[Nodeu[j+1+ i*(Ny+2)]-1]+ui[Nodeu[j  + i*(Ny+2)]-1]);
                    Uien = Uiws;
                }
                if (Nodev[j   +(i+1)*(Ny+1)]<=NbcsDv || Nodev[j   +(i+1)*(Ny+1)]>Nbcs) { //Dirichlet on v
                    Vj = 0.5*( vj[Nodev[j   +(i+1)*(Ny+1)]-1] +  vj[Nodev[j  +i*(Ny+1)]-1] );
                }
                else {
                    Vj = 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] );
                }
                
            }
            //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
                    Uiws = 0.5*(ui[Nodeu[j+1+ i*(Ny+2)]-1]+ui[Nodeu[j  + i*(Ny+2)]-1]);
                }
            }
            if(Nodeu[j-1+i*(Ny+2)]<=Nbcs && Nodeu[j-1+i*(Ny+2)]>NbcsDu) {
                //if the most south boundary is Neumann use CDS
                Uien =  0.5*(ui[Nodeu[j+1+ i*(Ny+2)]-1]+ui[Nodeu[j  + i*(Ny+2)]-1]);
            }
            fs = (0.5/dy)*( Uiws*(Vj+fabs(Vj)) + Uien*(Vj-fabs(Vj)) );
            
            //North Face
            if (Nodeu[j-1+ i*(Ny+2)]>Nbcs) {
                Uiws = 3.0/8.0*ui[Nodeu[j-1+ i*(Ny+2)]-1] +\
                        6.0/8.0*ui[Nodeu[j  + i*(Ny+2)]-1] -\
                        1.0/8.0*ui[Nodeu[j+1+ i*(Ny+2)]-1];
                Uien = 3.0/8.0*ui[Nodeu[j  + i*(Ny+2)]-1] +\
                        6.0/8.0*ui[Nodeu[j-1+ i*(Ny+2)]-1] -\
                        1.0/8.0*ui[Nodeu[j-2+ i*(Ny+2)]-1];
                Vj = 0.5*( vj[Nodev[j-1 +(i+1)*(Ny+1)]-1] + vj[Nodev[j-1+i*(Ny+1)]-1] );
            }
            else { //treat boundaries
                if (Nodeu[j-1+(i)*(Ny+2)]<=NbcsDu) { //Dirichlet on u
                    Uiws = 0.5*(ui[Nodeu[j  + i*(Ny+2)]-1]+ui[Nodeu[j-1+ i*(Ny+2)]-1]);
                    Uien = Uiws;
                }
                else { //Neuman on u
                    Uiws = (0.5*ui[Nodeu[j  + i*(Ny+2)]-1]+ui[Nodeu[j-1+ i*(Ny+2)]-1]);
                    Uien = Uiws;
                }
                if (Nodev[j-1 +(i+1)*(Ny+1)]<=NbcsDv || Nodev[j-1 +(i+1)*(Ny+1)]>Nbcs) { //Dirichlet on v
                    Vj = 0.5*( vj[Nodev[j-1 +(i+1)*(Ny+1)]-1] + vj[Nodev[j-1+i*(Ny+1)]-1] );
                }
                else { //Neuman on v
                    Vj = 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] );
                }
            }
            //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
                    Uien = 0.5*(ui[Nodeu[j  + i*(Ny+2)]-1]+ui[Nodeu[j-1+ i*(Ny+2)]-1]);
                }
            }
            if(Nodeu[j+1+i*(Ny+2)]<=Nbcs && Nodeu[j+1+i*(Ny+2)]>NbcsDu) {
                //if the most south boundary is Neumann use CDS
                Uiws = 0.5*(ui[Nodeu[j  + i*(Ny+2)]-1]+ui[Nodeu[j-1+ i*(Ny+2)]-1]);    
            }
            fn = (0.5/dy)*( Uiws*(Vj+fabs(Vj)) + Uien*(Vj-fabs(Vj)) );
            
            //Calculate Total flux change for this cell
            Fu[j-1+(i-1)*Ny] = fw-fe+fs-fn;
            }            
        }
    }
    
    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
                Uiws = 3.0/8.0*vi[Nodev[j  + i   *(Ny+1)]-1] +\
                        6.0/8.0*vi[Nodev[j  +(i-1)*(Ny+1)]-1] -\
                        1.0/8.0*vi[Nodev[j  +(i-2)*(Ny+1)]-1];
                Uien = 3.0/8.0*vi[Nodev[j  +(i-1)*(Ny+1)]-1] +\
                        6.0/8.0*vi[Nodev[j  +(i  )*(Ny+1)]-1] -\
                        1.0/8.0*vi[Nodev[j  +(i+1)*(Ny+1)]-1];
                Uj = 0.5*( uj[Nodeu[j+1 +(i-1)*(Ny+2)]-1] + uj[Nodeu[j +(i-1)*(Ny+2)]-1] );
            }
            else //treat boundary condition
            {
                //West face
                if (Nodev[j  +(i-1)*(Ny+1)]-1<=NbcsDv) { //dirichlet on v
                    Uiws = 0.5*(vi[Nodev[j  +(i-1)*(Ny+1)]-1]+vi[Nodev[j  +(i  )*(Ny+1)]-1]);
                    Uien = Uiws;
                }
                else { //Neuman on v
                    Uiws = (0.5*vi[Nodev[j  +(i-1)*(Ny+1)]-1]+vi[Nodev[j  +(i  )*(Ny+1)]-1]);
                    Uien = Uiws;
                }
                if (Nodeu[j+1 +(i-1)*(Ny+2)]<=NbcsDu || Nodeu[j+1 +(i-1)*(Ny+2)]>Nbcs) { //dirichlet on u
                    Uj = 0.5*( uj[Nodeu[j+1 +(i-1)*(Ny+2)]-1] + uj[Nodeu[j +(i-1)*(Ny+2)]-1] );
                }
                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] );
                }
            }
            //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
                    Uiws = 0.5*(vi[Nodev[j  +(i-1)*(Ny+1)]-1]+vi[Nodev[j  +(i  )*(Ny+1)]-1]);
                }
            }
            if(Nodev[j+(i+1)*(Ny+1)]<=Nbcs && Nodev[j+(i+1)*(Ny+1)]>NbcsDv) {
                //if the most east boundary is Neumann use CDS
                Uien = 0.5*(vi[Nodev[j  +(i-1)*(Ny+1)]-1]+vi[Nodev[j  +(i  )*(Ny+1)]-1]);         
            }
            fw = (0.5/dx)*(Uiws*(Uj+fabs(Uj)) + Uien*(Uj-fabs(Uj)) );
            
            if (Nodev[j  +(i+1)*(Ny+1)]>Nbcs) {
                //East face
                Uiws = 3.0/8.0*vi[Nodev[j  +(i+1)*(Ny+1)]-1] +\
                        6.0/8.0*vi[Nodev[j +(i  )*(Ny+1)]-1] -\
                        1.0/8.0*vi[Nodev[j +(i-1)*(Ny+1)]-1];
                Uien = 3.0/8.0*vi[Nodev[j  +(i  )*(Ny+1)]-1] +\
                        6.0/8.0*vi[Nodev[j +(i+1)*(Ny+1)]-1] -\
                        1.0/8.0*vi[Nodev[j +(i+2)*(Ny+1)]-1];
                Uj = 0.5*( uj[Nodeu[j+1 + i*(Ny+2)   ]-1] + uj[Nodeu[j  +i*(Ny+2)]-1] );
            }
            else //treat boundary condition
            {
                //East face
                if (Nodev[j  +(i+1)*(Ny+1)]-1<=NbcsDv) {//Dirichlet on v
                    Uiws = 0.5*(vi[Nodev[j  +(i  )*(Ny+1)]-1]+vi[Nodev[j  +(i+1)*(Ny+1)]-1]);
                    Uien = Uiws;
                }
                else { //Neumann on v
                    Uiws = (0.5*vi[Nodev[j  +(i  )*(Ny+1)]-1]+vi[Nodev[j  +(i+1)*(Ny+1)]-1]);
                    Uien = Uiws;
                }
                if (Nodeu[j+1 +(i)*(Ny+2)]<=NbcsDu || Nodeu[j+1 +(i)*(Ny+2)]>Nbcs) { //dirichlet on u
                    Uj = 0.5*( uj[Nodeu[j+1 + i*(Ny+2)   ]-1] + uj[Nodeu[j  +i*(Ny+2)]-1] );
                }
                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] );
                }
            }
            //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
                    Uien = 0.5*(vi[Nodev[j  +(i  )*(Ny+1)]-1]+vi[Nodev[j  +(i+1)*(Ny+1)]-1]);
                }
            }
            if(Nodev[j+(i-1)*(Ny+1)]<=Nbcs && Nodev[j+(i-1)*(Ny+1)]>NbcsDv) {
                //if the most west boundary is Neumann use CDS
                Uiws = 0.5*(vi[Nodev[j  +(i  )*(Ny+1)]-1]+vi[Nodev[j  +(i+1)*(Ny+1)]-1]);
            }
            fe = (0.5/dx)*(Uiws*(Uj+fabs(Uj)) + Uien*(Uj-fabs(Uj)) );
            
            if (Nodev[j+1+ i*(Ny+1)]>Nbcs) {
                //South Face
                Uiws = 3.0/8.0*vi[Nodev[j  + i*(Ny+1)]-1] +\
                        6.0/8.0*vi[Nodev[j+1+ i*(Ny+1)]-1] -\
                        1.0/8.0*vi[Nodev[j+2+ i*(Ny+1)]-1];
                Uien = 3.0/8.0*vi[Nodev[j+1+ i*(Ny+1)]-1] +\
                        6.0/8.0*vi[Nodev[j  + i*(Ny+1)]-1] -\
                        1.0/8.0*vi[Nodev[j-1+ i*(Ny+1)]-1];
                Ujws = 3.0/8.0*vj[Nodev[j  + i*(Ny+1)]-1] +\
                        6.0/8.0*vj[Nodev[j+1+ i*(Ny+1)]-1] -\
                        1.0/8.0*vj[Nodev[j+2+ i*(Ny+1)]-1];
                Ujen = 3.0/8.0*vj[Nodev[j+1+ i*(Ny+1)]-1] +\
                        6.0/8.0*vj[Nodev[j  + i*(Ny+1)]-1] -\
                        1.0/8.0*vj[Nodev[j-1+ i*(Ny+1)]-1];
            }
            else {
                if (Nodev[j+1+(i)*(Ny+1)]-1<=NbcsDv) {
                    Uiws = 0.5*(vi[Nodev[j+1+ i*(Ny+1)]-1]+vi[Nodev[j  + i*(Ny+1)]-1]);
                    Uien = Uiws;
                    Ujws = 0.5*(vj[Nodev[j+1+ i*(Ny+1)]-1]+vj[Nodev[j  + i*(Ny+1)]-1]);
                    Ujen = Ujws;
                }
                else {
                    Uiws = (0.5*vi[Nodev[j+1+ i*(Ny+1)]-1]+vi[Nodev[j  + i*(Ny+1)]-1]);
                    Uien = Uiws;
                    Ujws = (0.5*vj[Nodev[j+1+ i*(Ny+1)]-1]+vj[Nodev[j  + i*(Ny+1)]-1]);
                    Ujen = Ujws;
                }
            }
            //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
                    Uiws = 0.5*(vi[Nodev[j+1+ i*(Ny+1)]-1]+vi[Nodev[j  + i*(Ny+1)]-1]);
                    Ujws = 0.5*(vj[Nodev[j+1+ i*(Ny+1)]-1]+vj[Nodev[j  + i*(Ny+1)]-1]);
                }
            }
            if(Nodev[j-1+i*(Ny+1)]<=Nbcs && Nodev[j-1+i*(Ny+1)]>NbcsDv) {
                //if the most north boundary is Neumann use CDS
               Uien = 0.5*(vi[Nodev[j+1+ i*(Ny+1)]-1]+vi[Nodev[j  + i*(Ny+1)]-1]);
               Ujen = 0.5*(vj[Nodev[j+1+ i*(Ny+1)]-1]+vj[Nodev[j  + i*(Ny+1)]-1]); 
            }
            //Do some minor slope limiting
            if (j+2<=Ny) { 
                if (sign(vj[Nodev[j+1  + i*(Ny+1)]-1]) != sign(vj[Nodev[j+2  + i*(Ny+1)]-1]))
                {
                    Uiws  = vi[Nodev[j+1  +(i)*(Ny+1)]-1];
                    Ujws  = vj[Nodev[j+1  +(i)*(Ny+1)]-1];
                }                
            }
            if (sign(vj[Nodev[j-1  + i*(Ny+1)]-1]) != sign(vj[Nodev[j  + i*(Ny+1)]-1])) {
                Uien  = vi[Nodev[j  + i*(Ny+1)]-1];
                Ujen  = vj[Nodev[j  + i*(Ny+1)]-1];
            }
            fs = (0.5/dy)*( Uiws*(Ujws+fabs(Ujws)) + Uien*(Ujen-fabs(Ujen)) );
            
            //North Face
            if (Nodev[j-1+ i*(Ny+1)]>Nbcs) {
                Uiws = 3.0/8.0*vi[Nodev[j-1+ i*(Ny+1)]-1] +\
                        6.0/8.0*vi[Nodev[j  + i*(Ny+1)]-1] -\
                        1.0/8.0*vi[Nodev[j+1+ i*(Ny+1)]-1];
                Uien = 3.0/8.0*vi[Nodev[j  + i*(Ny+1)]-1] +\
                        6.0/8.0*vi[Nodev[j-1+ i*(Ny+1)]-1] -\
                        1.0/8.0*vi[Nodev[j-2+ i*(Ny+1)]-1];
                Ujws = 3.0/8.0*vj[Nodev[j-1+ i*(Ny+1)]-1] +\
                        6.0/8.0*vj[Nodev[j  + i*(Ny+1)]-1] -\
                        1.0/8.0*vj[Nodev[j+1+ i*(Ny+1)]-1];
                Ujen = 3.0/8.0*vj[Nodev[j  + i*(Ny+1)]-1] +\
                        6.0/8.0*vj[Nodev[j-1+ i*(Ny+1)]-1] -\
                        1.0/8.0*vj[Nodev[j-2+ i*(Ny+1)]-1];
            }
            else {
                if (Nodev[j-1+(i)*(Ny+1)]-1<=NbcsDv) {
                    Uiws = 0.5*(vi[Nodev[j  + i*(Ny+1)]-1]+vi[Nodev[j-1+ i*(Ny+1)]-1]);
                    Uien = Uiws;
                    Ujws = 0.5*(vj[Nodev[j  + i*(Ny+1)]-1]+vj[Nodev[j-1+ i*(Ny+1)]-1]);
                    Ujen = Ujws;
                }
                else {
                    Uiws = (0.5*vi[Nodev[j  + i*(Ny+1)]-1]+vi[Nodev[j-1+ i*(Ny+1)]-1]);
                    Uien = Uiws;
                    Ujws = (0.5*vj[Nodev[j  + i*(Ny+1)]-1]+vj[Nodev[j-1+ i*(Ny+1)]-1]);
                    Ujen = Ujws;
                }
            }
             //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
                    Uien = 0.5*(vi[Nodev[j  + i*(Ny+1)]-1]+vi[Nodev[j-1+ i*(Ny+1)]-1]);
                    Ujen = 0.5*(vj[Nodev[j  + i*(Ny+1)]-1]+vj[Nodev[j-1+ i*(Ny+1)]-1]);
                }
            }
            if(Nodev[j+1+i*(Ny+1)]<=Nbcs && Nodev[j+1+i*(Ny+1)]>NbcsDv) {
                //if the most south boundary is Neumann use CDS
               Uiws = 0.5*(vi[Nodev[j  + i*(Ny+1)]-1]+vi[Nodev[j-1+ i*(Ny+1)]-1]);
               Ujws = 0.5*(vj[Nodev[j  + i*(Ny+1)]-1]+vj[Nodev[j-1+ i*(Ny+1)]-1]);
            }
            //Do some minor slope limiting
            if (sign(vj[Nodev[j+1  + i*(Ny+1)]-1]) != sign(vj[Nodev[j  + i*(Ny+1)]-1])) {
                Uiws  = vi[Nodev[j  + i*(Ny+1)]-1];
                Ujws  = vj[Nodev[j  + i*(Ny+1)]-1];
            }
            if (j-2>=0) {
                if (sign(vj[Nodev[j-1  + i*(Ny+1)]-1]) != sign(vj[Nodev[j-2  + i*(Ny+1)]-1])) {
                    Uien  = vi[Nodev[j-1  + i*(Ny+1)]-1];
                    Ujen  = vj[Nodev[j-1  + i*(Ny+1)]-1];
                }
            }
            fn = (0.5/dy)*( Uiws*(Ujws+fabs(Ujws)) + Uien*(Ujen-fabs(Ujen)) );
            Fv[j-1+(i-1)*(Ny-1)] = fw-fe+fs-fn;
            }
        }
    }
}