//  DIRTABLE.C
//  © 2021 Peter J. Meyer

#include "iss.h"

static int inverse_dir[MAX_DIMENSIONALITY];

//  Set the values of the direction table based on the type of lattice.
//  For direction r, where 0 <= r < coord_num.
//  dir[r][n] is the value to add to index n of a given site
//  to get index n of the nearest neighbour in direction r.
/*--------------------------*/
void set_direction_table(void)
{
if ( square_lattice )
    {                                       //         0   1        |1
    dir[0][0] =  1;  dir[0][1] =  0;        //    0:  +1   0        |
    dir[1][0] = -1;  dir[1][1] =  0;        //    1:  -1   0     ---O--->j
    dir[2][0] =  0;  dir[2][1] =  1;        //    2:   0  +1     3  |  2
    dir[3][0] =  0;  dir[3][1] = -1;        //    3:   0  -1        |0
                                            //                      Vi
    }
else if ( triangular_lattice )
    {                                       //         0   1        
    dir[0][0] =  1;  dir[0][1] =  0;        //    0:  +1   0     5\ |1 
    dir[1][0] = -1;  dir[1][1] =  0;        //    1:  -1   0       \| 
    dir[2][0] =  0;  dir[2][1] =  1;        //    2:   0  +1    --- O --->j
    dir[3][0] =  0;  dir[3][1] = -1;        //    3:   0  -1    3   |\  2
    dir[4][0] =  1;  dir[4][1] =  1;        //    4:  +1  +1        |0\4 
    dir[5][0] = -1;  dir[5][1] = -1;        //    5:  -1  -1        Vi  
    }
else if ( double_triangular_lattice )
    {                                       //         0   1
    dir[0][0] =  1;  dir[0][1] =  0;        //    0:  +1   0        1
    dir[1][0] = -1;  dir[1][1] =  0;        //    1:  -1   0     5\ | /7
    dir[2][0] =  0;  dir[2][1] =  1;        //    2:   0  +1       \|/
    dir[3][0] =  0;  dir[3][1] = -1;        //    3:   0  -1    3---O--->j
    dir[4][0] =  1;  dir[4][1] =  1;        //    4:  +1  +1       /|\  2
    dir[5][0] = -1;  dir[5][1] = -1;        //    5:  -1  -1     6/ |0\4 
    dir[6][0] =  1;  dir[6][1] = -1;        //    6:  +1  -1        Vi  
    dir[7][0] = -1;  dir[7][1] =  1;        //    7:  -1  +1
    }
else if ( honeycomb_lattice )   
    {                    
    //  There are two varieties of honeycomb lattice.
    //  (But may not need to distinguish between them.)
    if ( major_axis == 0 )
        {
                                                //         0   1 
        dir[0][0] =  1;  dir[0][1] =  0;        //    0:  +1   0
        dir[1][0] = -1;  dir[1][1] =  0;        //    1:  -1   0
        dir[2][0] =  0;  dir[2][1] =  1;        //    2:   0  +1
        }
    else //  major_axis == 1
        {
        dir[0][0] =  0;  dir[0][1] =  1;        //    0:   0  +1
        dir[1][0] =  0;  dir[1][1] = -1;        //    1:   0  -1
        dir[2][0] =  1;  dir[2][1] =  0;        //    2:  +1   0
        }
    //  The third direction changes according to whether the site is odd or even.
    // 
    //  If the major axis is 0 then the directions are:
    //
    //       1|                                1|
    //        |                                 | 
    //        O--->j  if site even          ----0     if site odd     
    //        |   2                         2   |
    //        |0                                |0
    //        Vi                                Vi   
    // 
    //  If the major axis is 1 then the directions are:
    //                                          
    //                                         2|
    //                                          | 
    //     ---O--->j  if site even           ---0--->j     if site odd     
    //     1  |  0                           1     0 
    //        |2                                  
    //        Vi                                                             
    //
    //  If periodic boundary conditions are used then the size
    //  of the lattice in each dimension must be even.
    }
else if ( cubic_lattice )
    {                                                  //      0   1   2      1   
    dir[0][0] =  1;  dir[0][1] =  0;  dir[0][2] =  0;  // 0:  +1   0   0      | /3
    dir[1][0] = -1;  dir[1][1] =  0;  dir[1][2] =  0;  // 1:  -1   0   0  5   |/   
    dir[2][0] =  0;  dir[2][1] =  1;  dir[2][2] =  0;  // 2:   0  +1   0  ----O--->k
    dir[3][0] =  0;  dir[3][1] = -1;  dir[3][2] =  0;  // 3:   0  -1   0     /|   4   
    dir[4][0] =  0;  dir[4][1] =  0;  dir[4][2] =  1;  // 4:   0   0  +1   2/ |0      
    dir[5][0] =  0;  dir[5][1] =  0;  dir[5][2] = -1;  // 5:   0   0  -1  jL  Vi     
    }
else if ( quadrilateral_lattice )   
    {
    //  Same as cubic with two extra directions.
                                                       //      0   1   2  7  1  3 
    dir[0][0] =  1;  dir[0][1] =  0;  dir[0][2] =  0;  // 0:  +1   0   0   \ | /
    dir[1][0] = -1;  dir[1][1] =  0;  dir[1][2] =  0;  // 1:  -1   0   0 5  \|/   
    dir[2][0] =  0;  dir[2][1] =  1;  dir[2][2] =  0;  // 2:   0  +1   0 ----O--->k
    dir[3][0] =  0;  dir[3][1] = -1;  dir[3][2] =  0;  // 3:   0  -1   0    /|\  4   
    dir[4][0] =  0;  dir[4][1] =  0;  dir[4][2] =  1;  // 4:   0   0  +1  2/ |0\6    
    dir[5][0] =  0;  dir[5][1] =  0;  dir[5][2] = -1;  // 5:   0   0  -1 jL  Vi ijk
    dir[6][0] =  1;  dir[6][1] =  1;  dir[6][2] =  1;  // 6:  +1  +1  +1   
    dir[7][0] = -1;  dir[7][1] = -1;  dir[7][2] = -1;  // 7:  -1  -1  -1   
    }
else if ( tetrahedral_lattice )
    {
    #if !TETRAHEDRAL_LATTICE_IMPLEMENTED
    printf("\nTetrahedral lattice type not currently supported."
           "\nSee DIRTABLE.C\n");
    exit(1);
    #else
    //  This is the cubic lattice plus six diagonal bonds.
    //  Coordination number of 12, so requires bonds array to be >= short ints.
                                                       //       0   1   2  
    dir[0][0] =  1;  dir[0][1] =  0;  dir[0][2] =  0;  //  0:  +1   0   0   
    dir[1][0] = -1;  dir[1][1] =  0;  dir[1][2] =  0;  //  1:  -1   0   0  
    dir[2][0] =  0;  dir[2][1] =  1;  dir[2][2] =  0;  //  2:   0  +1   0  
    dir[3][0] =  0;  dir[3][1] = -1;  dir[3][2] =  0;  //  3:   0  -1   0 
    dir[4][0] =  0;  dir[4][1] =  0;  dir[4][2] =  1;  //  4:   0   0  +1  
    dir[5][0] =  0;  dir[5][1] =  0;  dir[5][2] = -1;  //  5:   0   0  -1  

    dir[6][0] =  1;  dir[0][1] = -1;  dir[0][2] =  0;  //  6:  +1  -1   0   
    dir[7][0] = -1;  dir[1][1] =  1;  dir[1][2] =  0;  //  7:  -1  +1   0  
    dir[8][0] =  1;  dir[2][1] =  0;  dir[2][2] = -1;  //  8:  +1   0  -1  
    dir[9][0] = -1;  dir[3][1] =  0;  dir[3][2] =  1;  //  9:  -1   0  +1 
    dir[10][0] = 0;  dir[4][1] =  1;  dir[4][2] = -1;  // 10:   0  +1  -1  
    dir[11][0] = 0;  dir[5][1] = -1;  dir[5][2] =  1;  // 11:   0  -1  +1  
    #endif
    }
else if ( diamond_lattice )
    {                     
    //  There are three varieties of diamond lattice: major axis = 0, 1 and 2.
    //  Diamond lattices with major axis 1 and 2 are equivalent, so we need
    //  consider only two varieties.
    if ( major_axis == 0 )
        { 
                                                           //         0   1   2   
        dir[0][0] =  1;  dir[0][1] =  0;  dir[0][2] =  0;  //    0:  +1   0   0   
        dir[1][0] = -1;  dir[1][1] =  0;  dir[1][2] =  0;  //    1:  -1   0   0   
        dir[2][0] =  0;  dir[2][1] =  1;  dir[2][2] =  0;  //    2:   0  +1   0   
        dir[3][0] =  0;  dir[3][1] =  0;  dir[3][2] =  1;  //    3:   0   0  +1 
        }
    else //  assume major_axis is 1
        { 
                                                           //         0   1   2   
        dir[0][0] =  0;  dir[0][1] =  1;  dir[0][2] =  0;  //    0:   0  +1   0   
        dir[1][0] =  0;  dir[1][1] = -1;  dir[1][2] =  0;  //    1:   0  -1   0   
        dir[2][0] =  1;  dir[2][1] =  0;  dir[2][2] =  0;  //    2:  +1   0   0   
        dir[3][0] =  0;  dir[3][1] =  0;  dir[3][2] =  1;  //    3:   0   0  +1 
        }      
    //  The last two directions change sign according to 
    //  whether the site is odd or even.
    // 
    //  If the major axis is 0 then the directions are:
    //
    //       1|                                1|
    //        |                                 | /2
    //        |                                 |/
    //        O--->k  if site even          ----0     if site odd     
    //       /|   3                          3  |
    //     2/ |0                                |0
    //     L  |                                 |
    //    j   Vi                                Vi  
    //
    //                                        
    //  If the major axis is 1 then the directions are:
    //
    //          /1                             2| /1
    //         /                                |/
    //        O--->k  if site even          3---0     if site odd     
    //       /|   3                            / 
    //     0/ |2                             0/    
    //     L  |                              L    
    //    j   Vi                            j       
    //
    //  If periodic boundary conditions are used then the size 
    //  of the lattice in each dimension must be even.
    }
else if ( hypercubic_lattice_4d )
    {                                                    //         0   1   2   3
    dir[0][0]= 1; dir[0][1]= dir[0][2]= dir[0][3] = 0;   //    0:  +1   0   0   0
    dir[1][0]=-1; dir[1][1]= dir[1][2]= dir[1][3] = 0;   //    1:  -1   0   0   0
    dir[2][0]= 0; dir[2][1]= 1; dir[2][2]= dir[2][3]= 0; //    2:   0  +1   0   0
    dir[3][0]= 0; dir[3][1]=-1; dir[3][2]= dir[3][3]= 0; //    3:   0  -1   0   0   
    dir[4][0]= dir[4][1]= 0; dir[4][2]= 1; dir[4][3]= 0; //    4:   0   0  +1   0
    dir[5][0]= dir[5][1]= 0; dir[5][2]=-1; dir[5][3]= 0; //    5:   0   0  -1   0
    dir[6][0]= dir[6][1]= dir[6][2]= 0; dir[6][3]= 1;    //    6:   0   0   0  +1
    dir[7][0]= dir[7][1]= dir[7][2]= 0; dir[7][3]=-1;    //    7:   0   0   0  -1
    }
else if ( hyperdiamond_lattice_4d )
    {                                                    //         0   1   2   3
    dir[0][0]= 1; dir[0][1]= dir[0][2]= dir[0][3] = 0;   //    0:  +1   0   0   0
    dir[1][0]=-1; dir[1][1]= dir[1][2]= dir[1][3] = 0;   //    1:  -1   0   0   0
    dir[2][0]= 0; dir[2][1]= 1; dir[2][2]= dir[2][3]= 0; //    2:   0  +1   0   0  
    dir[3][0]= dir[3][1]= 0; dir[3][2]= 1; dir[3][3]= 0; //    3:   0   0  +1   0
    dir[4][0]= dir[4][1]= dir[4][2]= 0; dir[4][3]= 1;    //    4:   0   0   0  +1
    }
    //  The last three directions change sign according to 
    //  whether the site is odd or even.
    //  If periodic boundary conditions are used then the size 
    //  of the lattice in each dimension must be even.
}

//  Given that the direction table is defined,
//  the directionality for a given direction 
//  is the weighted sum of the signs of the directions,
//  weighted by lowness of index.
//  This is used only in trace_single_cluster() in CLUSTERS.C.
/*---------------------------*/
void set_directionalities(void)
{
int r, index, sum;

if ( direction_table_is_parity_dependent )
    adjust_direction_table(0);

for ( r=0; r<coord_num; r++ )
    {
    sum = 0;
    for ( index=0; index<dimensionality; index++ )
        sum += dir[r][index]*(dimensionality-index);
    directionality[r] = sum;
    }
}

//  Given a site of a certain parity, and a direction to a nn site, 
//  this function returns the direction from the nn site back to the given site.
/*------------------------------------*/
int inverse_direction(int parity, int r)
{
int index, ir, nn_parity=parity;

if ( direction_table_is_parity_dependent )
    adjust_direction_table(parity);

for ( index=0; index<dimensionality; index++ )
    {
    inverse_dir[index] = -dir[r][index];
    nn_parity += abs(dir[r][index]);
    }

nn_parity %= 2;

if ( nn_parity != parity && direction_table_is_parity_dependent )
    adjust_direction_table(nn_parity);

for ( ir=0; ir<coord_num; ir++ )
    {
    for ( index=0; index<dimensionality; index++ )     
        {
        if ( dir[ir][index] != inverse_dir[index] )
            break;
        }
    if ( index == dimensionality )
        break;
    }

if ( ir == coord_num )
    {
    printf("\nError when getting inverse direction.\n");
    exit(1);
    }

if ( nn_parity != parity && direction_table_is_parity_dependent )
    adjust_direction_table(parity);

return ( ir );
}

//  Where lattice is parity-dependent this function is used
//  to adjust the direction table at odd or even sites.
/*-----------------------------------*/
void adjust_direction_table(int parity)
{
if ( honeycomb_lattice )
    dir[2][1-major_axis] = ( parity ? -1 : 1 );
else if ( diamond_lattice )
    dir[2][1-major_axis] = dir[3][2] = ( parity ? -1 : 1 ); 
else if ( hyperdiamond_lattice_4d )
    dir[2][1] = dir[3][2] = dir[4][3] = ( parity ? -1 : 1 );
}