/*****************************************************

  Copyright (C) 2011, 2012 Andrea Nobile

  

*******************************************************/


#define MAIN_PROGRAM

#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "mpi.h"
#include "su3.h"
#include "random.h"
#include "start.h"
#include "misc.h"
#include "update.h"
#include "linalg.h"
#include "block.h"
#include "sw_term.h"
#include "dirac.h"
#include "sap_gcr.h"
#include "global.h"
#include "init.h"
#include "dds_interface.h"

int _dd_init = 0;

extern spinor_dble *_dds_src;
extern spinor_dble *_dds_dst;
extern spinor_dble *_dds_tmp;

int _ndfl;
int _blkrel;

void _dds_init_internal(dds_lat_grid par, int extern_topology)
{

  int i;
  int *p;
  su3 **mpu;
  su3_dble **mpud;
  spinor_dble **wsd;


  if(!_dd_init) {
#ifndef COMPILETIME_SIZE
  //printf("initializing dd...\n");

  
  NPROC0 = par.np[0];
  NPROC1 = par.np[1];
  NPROC2 = par.np[2];
  NPROC3 = par.np[3];
  
  L0 = par.gl[0]/NPROC0;
  L1 = par.gl[1]/NPROC1;
  L2 = par.gl[2]/NPROC2;
  L3 = par.gl[3]/NPROC3;
  
  if( ((NPROC0<1)||(NPROC1<1)||(NPROC2<1)||(NPROC3<1)||		   
    ((NPROC0>1)&&((NPROC0%2)!=0))||((NPROC1>1)&&((NPROC1%2)!=0))|| 
       ((NPROC2>1)&&((NPROC2%2)!=0))||((NPROC3>1)&&((NPROC3%2)!=0))) ) {
    
    printf("The number of processes in each direction must be 1 or a multiple of 2\n");
    exit(1);

    }
  if (((L0<4)||(L1<4)||(L2<4)||(L3<4)|| 
       ((L0%2)!=0)||((L1%2)!=0)||((L2%2)!=0)||((L3%2)!=0))) {

    printf("The local lattice sizes must be even and not smaller than 4\n");
    exit(1);
  }
  

  NPROC = (NPROC0*NPROC1*NPROC2*NPROC3);
  //printf("nproc = %d\n", NPROC);
  VOLUME = (L0*L1*L2*L3);
  FACE0 = ((1-(NPROC0%2))*L1*L2*L3);
  FACE1 = ((1-(NPROC1%2))*L2*L3*L0);
  FACE2 = ((1-(NPROC2%2))*L3*L0*L1);
  FACE3 = ((1-(NPROC3%2))*L0*L1*L2);
  BNDRY = (2*(FACE0+FACE1+FACE2+FACE3));
  NSPIN = (VOLUME+(BNDRY/2));
  

  map = malloc((BNDRY+(NPROC%2))*sizeof(int));
  ipt = malloc(sizeof(int)*VOLUME);
    
  

  
  p = malloc(sizeof(int)*VOLUME*4);
  iup = malloc(sizeof(int*)*VOLUME);
  for(i=0;i<VOLUME;i++) {
    iup[i]=&p[4*i];
  }

  p = malloc(sizeof(int)*VOLUME*4);
  idn = malloc(sizeof(int*)*VOLUME);
  for(i=0;i<VOLUME;i++) {
    idn[i]=&p[4*i];
  }
  
  mpu = malloc(sizeof(su3*)*VOLUME*4);
  pu = malloc(sizeof(su3**)*VOLUME);
  for(i=0;i<VOLUME;i++) {
    pu[i]=&mpu[4*i];
  }

  mpud = malloc(sizeof(su3_dble*)*VOLUME*4);
  pud = malloc(sizeof(su3_dble**)*VOLUME);
  for(i=0;i<VOLUME;i++) {
    pud[i]=&mpud[4*i];
  }
  
  
#endif

  //start_ranlux(0,12345);
  if(extern_topology) {
    geometry_flex(&par);
    //geometry();
    /*  check rank  */
    int mr;
    
    MPI_Comm_rank(MPI_COMM_WORLD,&mr);
    if(mr != par.id) fprintf(stderr, "mismatch in mpi_rank dds = %d caller = %d\n", mr, par.id);
  } else {
    geometry();

  }
  
  alloc_u();
  alloc_ud();
  alloc_swd();

  no_s=0;
  alloc_sd(4); //
  //#warning rimetti 4

  
  wsd=reserve_wsd(3);
  _dds_src=wsd[0];
  _dds_dst=wsd[1];
  _dds_tmp=wsd[2];

  _dd_init=1;
  }
  
  
}


