/* This file is part of the Neper software package. */
/* Cgeomyright (C) 2003-2014, Romain Quey. */
/* See the COPYING file in the tgeom-level directory. */

#include "neut_tesr_geom_.h"

int
neut_tesr_point_pos (struct TESR Tesr, double *coo, int *rptpos)
{
  int i;

  for (i = 0; i < Tesr.Dim; i++)
  {
    if (coo[i] < 0 || coo[i] > Tesr.size[i] * Tesr.vsize[i])
      return -1;

    rptpos[i] = ceil (coo[i] / Tesr.vsize[i] + 1e-6);
    rptpos[i] = ut_num_min_int (rptpos[i], Tesr.size[i]);
  }
  for (i = Tesr.Dim; i < 3; i++)
    rptpos[i] = 1;

  return 0;
}

int
neut_tesr_coo (struct TESR Tesr, int *rptpos, double *coo)
{
  int i;

  for (i = 0; i < Tesr.Dim; i++)
  {
    if (rptpos[i] < 1 || rptpos[i] > Tesr.size[i])
      return -1;

    coo[i] = (rptpos[i] - 0.5) * Tesr.vsize[i];
  }

  return 0;
}

int
neut_tesr_cell_volume (struct TESR Tesr, int cell, double *pvol)
{
  int i, j, k;

  if (Tesr.Dim != 3)
  {
    (*pvol) = 0;
    return -1;
  }

  (*pvol) = 0;
  for (k = 1; k <= Tesr.size[2]; k++)
    for (j = 1; j <= Tesr.size[1]; j++)
      for (i = 1; i <= Tesr.size[0]; i++)
	if (Tesr.VoxCell[i][j][k] == cell)
	  (*pvol)++;

  (*pvol) *= (Tesr.vsize[0] * Tesr.vsize[1] * Tesr.vsize[2]);

  return 0;
}

int
neut_tesr_cell_centre (struct TESR Tesr, int cell, double *coo)
{
  int i, j, k, qty;
  int *rptpos = ut_alloc_1d_int (3);
  double *rptcoo = ut_alloc_1d (3);

  qty = 0;
  ut_array_1d_zero (coo, 3);
  for (k = 1; k <= Tesr.size[2]; k++)
    for (j = 1; j <= Tesr.size[1]; j++)
      for (i = 1; i <= Tesr.size[0]; i++)
	if (Tesr.VoxCell[i][j][k] == cell)
	{
	  ut_array_1d_int_set_3 (rptpos, i, j, k);
	  neut_tesr_coo (Tesr, rptpos, rptcoo);
	  ut_array_1d_add (coo, rptcoo, 3, coo);
	  qty++;
	}

  if (qty > 0)
    ut_array_1d_scale (coo, 3, 1. / qty);

  ut_free_1d_int (rptpos);
  ut_free_1d (rptcoo);

  return (qty > 0) ? 0 : -1;
}

void
neut_tesr_cellprop (struct TESR Tesr, double **centre, double* size)
{
  int i, j, k, cell;
  double rptsize = ut_array_1d_prod (Tesr.vsize, Tesr.Dim);

  ut_array_2d_zero (centre + 1, Tesr.CellQty, 3);
  ut_array_1d_zero (size + 1, Tesr.CellQty);

  for (k = 1; k <= Tesr.size[2]; k++)
    for (j = 1; j <= Tesr.size[1]; j++)
      for (i = 1; i <= Tesr.size[0]; i++)
      {
	cell = Tesr.VoxCell[i][j][k];

	centre[cell][0] += (i - 0.5);
	centre[cell][1] += (j - 0.5);
	centre[cell][2] += (k - 0.5);
	size[cell]++;
      }

  for (i = 1; i <= Tesr.CellQty; i++)
  {
    ut_array_1d_scale (centre[i], 3, 1. / size[i]);
    for (j = 0; j < 3; j++)
      centre[i][j] *= Tesr.vsize[j];

    size[i] *= rptsize;
  }

  return;
}

void
neut_tesr_centre (struct TESR Tesr, double* coo)
{
  int i;
  
  for (i = 0; i < 3; i++)
    coo[i] = 0.5 * Tesr.vsize[i] * Tesr.size[i];

  return;
}

void
neut_tesr_cell_diameq (struct TESR Tesr, int cell, double *pval)
{
  if (Tesr.Dim == 3)
  {
    neut_tesr_cell_volume (Tesr, cell, pval);
    (*pval) = pow ((6 / M_PI) * (*pval), 0.3333333333333333333333333);
  }

  else
    abort ();

  return;
}
