/*
 *  DistMatrix.c
 *
 *    routines for handling of distributed dynamic arrays in C
 *    Distribution: column-block
 */

#include <errno.h>
#include <stdlib.h>
#include <mpi.h>
#include "DistMatrix.h"

void newDistMatrix(DistMatrix *ar, int n, int m) {
  /* creates local part of global n x m array */
  int   myId, nTasks;
  int   lx, dx;
  int   flag;
 
  /* check, if MPI already running */
  MPI_Initialized(&flag);
  if (flag == 0) {
    MPI_Init(NULL, NULL);
  }

  MPI_Comm_rank(MPI_COMM_WORLD, &myId);
  MPI_Comm_size(MPI_COMM_WORLD, &nTasks);
  
  /* get size and offset of local array */
  blockDistribute(n, nTasks, myId, &lx, &dx);

  if ( MPI_Alloc_mem((MPI_Aint)lx*n*sizeof(TYPE), MPI_INFO_NULL, &(ar->data))
       == 0 ) {
    ar->nx = m;
    ar->ny = n;
    ar->lx = lx;
    ar->ly = n;
    ar->dx = dx;
  } else {
    perror("DistMatrix");
    MPI_Finalize();
    exit(-1);
  }
}


void deleteDistMatrix(DistMatrix ar) {
   MPI_Free_mem(ar.data);
}

void blockDistribute(int n, int nt, int id, int *count, int *offset) {
  /* block distribution of n elements on nt tasks */
  /* get number of elements (count) and offset for task id */

  *count  = n/nt;
  *offset = id * (n/nt);
  if (id < (n%nt)) {
    (*count)++;
    *offset += id;
  } else {
    *offset += n%nt;
  }
}