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

#include "neut_tesr_op_.h"

void
neut_tesr_set_zero (struct TESR *pTesr)
{
  (*pTesr).size = NULL;
  (*pTesr).vsize = NULL;
  (*pTesr).VoxCell = NULL;
  (*pTesr).CellQty = 0;
  (*pTesr).Dim = 0;
  (*pTesr).CellId = NULL;
  (*pTesr).CellOri = NULL;
  (*pTesr).SeedCoo = NULL;
  (*pTesr).SeedWeight = NULL;

  return;
}

void
neut_tesr_alloc (struct TESR *pTesr, int dim, int *size, double *vsize)
{
  (*pTesr).Dim = dim;

  if ((*pTesr).size == NULL || size != (*pTesr).size)
  {
    (*pTesr).size = ut_realloc_1d_int ((*pTesr).size, 3);
    ut_array_1d_int_set ((*pTesr).size, 3, 1);
    ut_array_1d_int_memcpy ((*pTesr).size, dim, size);
  }

  if (vsize != (*pTesr).vsize)
  {
    (*pTesr).vsize = ut_realloc_1d ((*pTesr).vsize, 3);
    ut_array_1d_set ((*pTesr).vsize, 3, 1);
    ut_array_1d_memcpy ((*pTesr).vsize, dim, vsize);
  }

  // FIXME for memory usage
  (*pTesr).VoxCell = ut_alloc_3d_int (size[0] + 2, size[1] + 2, size[2] + 2);

  return;
}

void
neut_tesr_free (struct TESR *pTesr)
{
  if ((*pTesr).size)
  {
    ut_free_3d_int ((*pTesr).VoxCell, (*pTesr).size[0] + 2,
		    (*pTesr).size[1] + 2);
    ut_free_1d_int ((*pTesr).size);
  }

  ut_free_1d ((*pTesr).vsize);

  (*pTesr).size = NULL;
  (*pTesr).vsize = NULL;
  (*pTesr).VoxCell = NULL;

  ut_free_1d_int ((*pTesr).CellId);
  (*pTesr).CellId = NULL;

  if ((*pTesr).CellOri)
  {
    ut_free_2d ((*pTesr).CellOri, (*pTesr).CellQty + 1);
    (*pTesr).CellOri = NULL;
  }

  if ((*pTesr).SeedCoo)
  {
    ut_free_2d ((*pTesr).SeedCoo, (*pTesr).CellQty + 1);
    (*pTesr).SeedCoo = NULL;
  }

  ut_free_1d ((*pTesr).SeedWeight);
  (*pTesr).SeedWeight = NULL;

  return;
}

void
neut_tesr_memcpy (struct TESR Tesr1, struct TESR *pTesr2)
{
  neut_tesr_memcpy_parms (Tesr1, pTesr2);

  (*pTesr2).VoxCell = ut_alloc_3d_int ((*pTesr2).size[0] + 2,
				      (*pTesr2).size[1] + 2,
				      (*pTesr2).size[2] + 2);
  ut_array_3d_int_memcpy ((*pTesr2).VoxCell, (*pTesr2).size[0] + 2,
			  (*pTesr2).size[1] + 2, (*pTesr2).size[2] + 2,
			  Tesr1.VoxCell);

  return;
}

void
neut_tesr_memcpy_parms (struct TESR Tesr1, struct TESR *pTesr2)
{
  neut_tesr_free (pTesr2);

  (*pTesr2).Dim = Tesr1.Dim;

  (*pTesr2).size = ut_alloc_1d_int (3);
  ut_array_1d_int_memcpy ((*pTesr2).size, 3, Tesr1.size);

  (*pTesr2).vsize = ut_alloc_1d (3);
  ut_array_1d_memcpy ((*pTesr2).vsize, 3, Tesr1.vsize);

  (*pTesr2).CellQty = Tesr1.CellQty;

  if (Tesr1.CellId)
  {
    (*pTesr2).CellId = ut_alloc_1d_int ((*pTesr2).CellQty + 1);
    ut_array_1d_int_memcpy ((*pTesr2).CellId + 1, (*pTesr2).CellQty,
	                    Tesr1.CellId + 1);
  }

  if (Tesr1.CellOri)
  {
    (*pTesr2).CellOri = ut_alloc_2d ((*pTesr2).CellQty + 1, 4);
    ut_array_2d_memcpy ((*pTesr2).CellOri + 1, (*pTesr2).CellQty, 4,
	                Tesr1.CellOri + 1);
  }

  if (Tesr1.SeedCoo)
  {
    (*pTesr2).SeedCoo = ut_alloc_2d ((*pTesr2).CellQty + 1, 3);
    ut_array_2d_memcpy ((*pTesr2).SeedCoo + 1, (*pTesr2).CellQty, 3,
	                Tesr1.SeedCoo + 1);
  }

  if (Tesr1.SeedWeight)
  {
    (*pTesr2).SeedWeight = ut_alloc_1d ((*pTesr2).CellQty + 1);
    ut_array_1d_memcpy ((*pTesr2).SeedWeight + 1, (*pTesr2).CellQty,
	                Tesr1.SeedWeight + 1);
  }

  return;
}

int
neut_tesr_expr_cells (struct TESR Tesr, char *expr, int **pcell, int *pcellqty)
{
  int i, id;
  FILE *file;
  (*pcellqty) = 0;

  if (Tesr.Dim != 3)
    ut_error_reportbug ();

  if (strcmp (expr, "all") == 0)
  {
    (*pcellqty) = Tesr.CellQty;
    (*pcell) = ut_alloc_1d_int (*pcellqty);
    for (i = 0; i < Tesr.CellQty; i++)
      (*pcell)[i] = i + 1;
  }

  else if (expr[0] == '@')
  {
    file = ut_file_open (expr + 1, "r");
    while (fscanf (file, "%d", &id) != EOF)
    {
      (*pcellqty)++;
      (*pcell) = ut_realloc_1d_int (*pcell, *pcellqty);
      (*pcell)[(*pcellqty) - 1] = id;
    }
    ut_file_close (file, expr + 1, "r");
  }
  else
  {
    int var_qty = 1;
    char **vars = ut_alloc_2d_char (var_qty, 15);
    double *vals = ut_alloc_1d (var_qty);
    int status;
    double res;

    sprintf (vars[0], "id");

    for (i = 1; i <= Tesr.CellQty; i++)
    {
      vals[0] = i;
#ifdef HAVE_LIBMATHEVAL
      status = ut_math_eval (expr, var_qty, vars, vals, &res);
#else
      ut_print_messagewnc (2, 72,
			   "This capability is not available because this version of Neper has not been compiled with libmatheval.");
      abort ();
#endif
      if (status == -1)
	abort ();
      if (res == 1)
      {
	(*pcellqty)++;
	(*pcell) = ut_realloc_1d_int (*pcell, *pcellqty);
	(*pcell)[(*pcellqty) - 1] = i;
      }
    }

    ut_free_2d_char (vars, var_qty);
    ut_free_1d (vals);
  }

  return 0;
}

void
neut_tesr_bbox (struct TESR Tesr, double **bbox)
{
  int i;

  ut_array_2d_set (bbox, 3, 1, 0);

  for (i = 0; i < 3; i++)
    bbox[i][1] = Tesr.size[i] * Tesr.vsize[i];

  return;
}

void
neut_tesr_scale (struct TESR *pTesr, double scale1, double scale2,
		double scale3, char *method)
{
  int i;
  double *scale = ut_alloc_1d (3);

  scale[0] = scale1;
  scale[1] = scale2;
  scale[2] = scale3;

  if (method == NULL)
    for (i = 0; i < (*pTesr).Dim; i++)
      (*pTesr).vsize[i] *= scale[i];

  ut_free_1d (scale);

  return;
}

void
neut_tesr_rasterscale (struct TESR *pTesr, double scale1, double scale2,
		       double scale3)
{
  int i, j, k, l, m, n, qty;
  struct TESR Tesr2;
  int **pos = NULL;
  double *scale = NULL;

  if (ut_num_requal (scale1, 1, 1e-6)
   && ut_num_requal (scale2, 1, 1e-6)
   && ut_num_requal (scale3, 1, 1e-6))
    return;

  pos = ut_alloc_2d_int (3, 2);
  scale = ut_alloc_1d (3);

  srand48 (1);
  scale[0] = scale1;
  scale[1] = scale2;
  scale[2] = scale3;

  neut_tesr_set_zero (&Tesr2);
  neut_tesr_memcpy_parms (*pTesr, &Tesr2);

  Tesr2.Dim = (*pTesr).Dim;

  Tesr2.CellQty = (*pTesr).CellQty;

  for (i = 0; i < (*pTesr).Dim; i++)
  {
    Tesr2.size[i] = (*pTesr).size[i] * scale[i];
    scale[i] = (double) Tesr2.size[i] / (*pTesr).size[i];
  }

  for (i = 0; i < 3; i++)
    Tesr2.vsize[i] = (*pTesr).vsize[i] / scale[i];

  Tesr2.VoxCell =
    ut_alloc_3d_int (Tesr2.size[0] + 2, Tesr2.size[1] + 2, Tesr2.size[2] + 2);

  for (k = 1; k <= Tesr2.size[2]; k++)
  {
    if (Tesr2.Dim == 3)
    {
      pos[2][0] = 1 + (double) (k - 1) / scale[2];
      pos[2][1] = 1 + (double) (k - 1e-6) / scale[2];
    }
    else
      ut_array_1d_int_set (pos[2], 2, 1);

    for (j = 1; j <= Tesr2.size[1]; j++)
    {
      if (Tesr2.Dim >= 2)
      {
	pos[1][0] = 1 + (double) (j - 1) / scale[1];
	pos[1][1] = 1 + (double) (j - 1e-6) / scale[1];
      }
      else
	ut_array_1d_int_set (pos[1], 2, 1);

      for (i = 1; i <= Tesr2.size[0]; i++)
      {
	pos[0][0] = 1 + (double) (i - 1) / scale[0];
	pos[0][1] = 1 + (double) (i - 1e-6) / scale[0];

	if (scale1 < 1 || scale2 < 1 || scale3 < 1)
	{
	  qty =
	    (pos[2][1] - pos[2][0] + 1) * (pos[1][1] - pos[1][0] +
					   1) * (pos[0][1] - pos[0][0] + 1);
	  int *array = ut_alloc_1d_int (qty);
	  int **val = NULL;
	  int valqty, qty2;

	  qty = 0;
	  for (n = pos[2][0]; n <= pos[2][1]; n++)
	    for (m = pos[1][0]; m <= pos[1][1]; m++)
	      for (l = pos[0][0]; l <= pos[0][1]; l++)
		array[qty++] = (*pTesr).VoxCell[l][m][n];

	  ut_array_1d_int_valqty (array, qty, &val, &valqty);

	  int *perm = ut_alloc_1d_int (valqty);
	  ut_array_1d_int_sort_index (val[1], valqty, perm);
	  ut_array_1d_int_reverseelts (perm, valqty);
	  ut_array_1d_permutation_int (val[0], valqty, perm);
	  ut_array_1d_permutation_int (val[1], valqty, perm);
	  ut_free_1d_int (perm);

	  if (valqty == 0)
	    ut_error_reportbug ();
	  else if (valqty == 1)
	    Tesr2.VoxCell[i][j][k] = val[0][0];
	  else
	  {
	    qty2 = ut_array_1d_int_nbofthisval (val[1], valqty, val[1][0]);

	    if (qty2 == 1)
	      Tesr2.VoxCell[i][j][k] = val[0][0];
	    else
	      Tesr2.VoxCell[i][j][k] = val[0][0];
	      // FIXME
	      // Tesr2.VoxCell[i][j][k] = val[0][(int) (drand48 () * qty2)];
	  }

	  ut_free_1d_int (array);
	  ut_free_2d_int (val, 2);
	}

	else
	{
	  double *coo = ut_alloc_1d (3);
	  int *pos = ut_alloc_1d_int (3);

	  ut_array_1d_int_set_3 (pos, i, j, k);

	  neut_tesr_coo (Tesr2, pos, coo);
	  neut_tesr_point_pos (*pTesr, coo, pos);

	  Tesr2.VoxCell[i][j][k] = (*pTesr).VoxCell[pos[0]][pos[1]][pos[2]];

	  ut_free_1d_int (pos);
	  ut_free_1d (coo);
	}
      }
    }
  }

  neut_tesr_free (pTesr);
  neut_tesr_memcpy (Tesr2, pTesr);
  neut_tesr_free (&Tesr2);

  ut_free_2d_int (pos, 3);
  ut_free_1d (scale);

  return;
}

void
neut_tesr_cells_rptqty (struct TESR Tesr, int **prptqty)
{
  int i, j, k;

  ut_free_1d_int (*prptqty);

  (*prptqty) = ut_alloc_1d_int (Tesr.CellQty + 1);

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

  return;
}

void
neut_tesr_cell_tesr (struct TESR Tesr, int cell, struct TESR *pCellTesr)
{
  int i, j, k;

  neut_tesr_memcpy_parms (Tesr, pCellTesr);

  (*pCellTesr).CellQty = 1;
  (*pCellTesr).VoxCell
    = ut_alloc_3d_int (Tesr.size[0] + 2, Tesr.size[1] + 2, Tesr.size[2] + 2);

  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)
	  (*pCellTesr).VoxCell[i][j][k] = cell;

  return;
}

void
neut_tesr_cell_pos_neighpos (struct TESR Tesr, int cell, int *pos, int dim,
			    int ***ppos, int *pqty)
{
  int *array = ut_alloc_1d_int (1);
  array[0] = cell;

  neut_tesr_cells_pos_neighpos (Tesr, array, 1, pos, dim, ppos, pqty);

  ut_free_1d_int (array);

  return;
}

// cell == NULL has a special behaviour: it takes all cells
// cellqty = -1 takes all cells + void (VoxCell = 0)
void
neut_tesr_cells_pos_neighpos (struct TESR Tesr, int *cell, int cellqty, int *pos,
			      int dim, int ***ppos, int *pqty)
{
  if (Tesr.Dim == 3)
    neut_tesr_cells_pos_neighpos_3d (Tesr, cell, cellqty, pos, dim, ppos, pqty);
  else if (Tesr.Dim == 2)
    neut_tesr_cells_pos_neighpos_2d (Tesr, cell, cellqty, pos, dim, ppos, pqty);
  else
    ut_error_reportbug ();

  return;
}

void
neut_tesr_cells_pos_neighpos_3d (struct TESR Tesr, int *cell, int cellqty, int *pos,
			         int dim, int ***ppos, int *pqty)
{
  int i, j, vqty;
  int **v = NULL;
  int *rptpos = ut_alloc_1d_int (3);

  if (Tesr.Dim != 3)
    ut_error_reportbug ();

  /*
     if (*ppos != NULL)
     ut_free_2d_int (*ppos, *pqty);
  */

  // check memory leak
  (*pqty) = 0;
  (*ppos) = NULL;

  if (dim == 0)
  {
    vqty = 26;
    v = ut_alloc_2d_int (vqty, 3);
    ut_array_1d_int_set_3 (v[0], -1, -1, -1);
    ut_array_1d_int_set_3 (v[1], -1, -1, 0);
    ut_array_1d_int_set_3 (v[2], -1, -1, 1);
    ut_array_1d_int_set_3 (v[3], -1, 0, -1);
    ut_array_1d_int_set_3 (v[4], -1, 0, 0);
    ut_array_1d_int_set_3 (v[5], -1, 0, 1);
    ut_array_1d_int_set_3 (v[6], -1, 1, -1);
    ut_array_1d_int_set_3 (v[7], -1, 1, 0);
    ut_array_1d_int_set_3 (v[8], -1, 1, 1);
    ut_array_1d_int_set_3 (v[9], 0, -1, -1);
    ut_array_1d_int_set_3 (v[10], 0, -1, 0);
    ut_array_1d_int_set_3 (v[11], 0, -1, 1);
    ut_array_1d_int_set_3 (v[12], 0, 0, -1);
    ut_array_1d_int_set_3 (v[13], 0, 0, 1);
    ut_array_1d_int_set_3 (v[14], 0, 1, -1);
    ut_array_1d_int_set_3 (v[15], 0, 1, 0);
    ut_array_1d_int_set_3 (v[16], 0, 1, 1);
    ut_array_1d_int_set_3 (v[17], 1, -1, -1);
    ut_array_1d_int_set_3 (v[18], 1, -1, 0);
    ut_array_1d_int_set_3 (v[19], 1, -1, 1);
    ut_array_1d_int_set_3 (v[20], 1, 0, -1);
    ut_array_1d_int_set_3 (v[21], 1, 0, 0);
    ut_array_1d_int_set_3 (v[22], 1, 0, 1);
    ut_array_1d_int_set_3 (v[23], 1, 1, -1);
    ut_array_1d_int_set_3 (v[24], 1, 1, 0);
    ut_array_1d_int_set_3 (v[25], 1, 1, 1);
  }

  else if (dim == 1)
  {
    vqty = 18;
    v = ut_alloc_2d_int (vqty, 3);
    ut_array_1d_int_set_3 (v[0], -1, -1, 0);
    ut_array_1d_int_set_3 (v[1], -1, 0, -1);
    ut_array_1d_int_set_3 (v[2], -1, 0, 0);
    ut_array_1d_int_set_3 (v[3], -1, 0, 1);
    ut_array_1d_int_set_3 (v[4], -1, 1, 0);
    ut_array_1d_int_set_3 (v[5], 0, -1, -1);
    ut_array_1d_int_set_3 (v[6], 0, -1, 0);
    ut_array_1d_int_set_3 (v[7], 0, -1, 1);
    ut_array_1d_int_set_3 (v[8], 0, 0, -1);
    ut_array_1d_int_set_3 (v[9], 0, 0, 1);
    ut_array_1d_int_set_3 (v[10], 0, 1, -1);
    ut_array_1d_int_set_3 (v[11], 0, 1, 0);
    ut_array_1d_int_set_3 (v[12], 0, 1, 1);
    ut_array_1d_int_set_3 (v[13], 1, -1, 0);
    ut_array_1d_int_set_3 (v[14], 1, 0, -1);
    ut_array_1d_int_set_3 (v[15], 1, 0, 0);
    ut_array_1d_int_set_3 (v[16], 1, 0, 1);
    ut_array_1d_int_set_3 (v[17], 1, 1, 0);
  }

  else if (dim == 2)
  {
    vqty = 6;
    v = ut_alloc_2d_int (vqty, 3);
    ut_array_1d_int_set_3 (v[0], -1, 0, 0);
    ut_array_1d_int_set_3 (v[1], 1, 0, 0);
    ut_array_1d_int_set_3 (v[2], 0, -1, 0);
    ut_array_1d_int_set_3 (v[3], 0, 1, 0);
    ut_array_1d_int_set_3 (v[4], 0, 0, -1);
    ut_array_1d_int_set_3 (v[5], 0, 0, 1);
  }

  else
    abort ();

  for (i = 0; i < vqty; i++)
  {
    ut_array_1d_int_add (pos, v[i], 3, rptpos);

    int skip = 0;
    for (j = 0; !skip && j < 3; j++)
      if (rptpos[j] < 1 || rptpos[j] > Tesr.size[j])
	skip = 1;

    if (skip)
      continue;

    if ((cell == NULL && cellqty == -1)
	|| (cell == NULL && cellqty == 0
	    && Tesr.VoxCell[rptpos[0]][rptpos[1]][rptpos[2]] != 0)
	|| ut_array_1d_int_eltpos (cell, cellqty,
				   Tesr.VoxCell[rptpos[0]][rptpos[1]][rptpos
								     [2]]) !=
	-1)
    {
      (*pqty)++;
      (*ppos) = ut_realloc_2d_int_addline (*ppos, *pqty, 3);
      ut_array_1d_int_memcpy ((*ppos)[(*pqty) - 1], 3, rptpos);
    }
  }

  ut_free_2d_int (v, vqty);
  ut_free_1d_int (rptpos);

  return;
}

// cell == NULL has a special behaviour: it takes all cells
// cellqty = -1 takes all cells + void (VoxCell = 0)
void
neut_tesr_cells_pos_neighpos_2d (struct TESR Tesr, int *cell, int cellqty, int *pos,
			         int dim, int ***ppos, int *pqty)
{
  int i, j, vqty;
  int **v = NULL;
  int *rptpos = ut_alloc_1d_int (3);

  if (Tesr.Dim != 2)
    ut_error_reportbug ();

  // check memory leak
  (*pqty) = 0;
  (*ppos) = NULL;

  if (dim == 0)
  {
    vqty = 8;
    v = ut_alloc_2d_int (vqty, 2);
    ut_array_1d_int_set_2 (v[0], -1, -1);
    ut_array_1d_int_set_2 (v[1], -1,  0);
    ut_array_1d_int_set_2 (v[2], -1,  1);
    ut_array_1d_int_set_2 (v[3],  0, -1);
    ut_array_1d_int_set_2 (v[4],  0,  1);
    ut_array_1d_int_set_2 (v[5],  1, -1);
    ut_array_1d_int_set_2 (v[6],  1,  0);
    ut_array_1d_int_set_2 (v[7],  1,  1);
  }

  else if (dim == 1)
  {
    vqty = 4;
    v = ut_alloc_2d_int (vqty, 2);
    ut_array_1d_int_set_2 (v[0], -1,  0);
    ut_array_1d_int_set_2 (v[1],  1,  0);
    ut_array_1d_int_set_2 (v[2],  0, -1);
    ut_array_1d_int_set_2 (v[3],  0,  1);
  }

  else
    abort ();

  for (i = 0; i < vqty; i++)
  {
    ut_array_1d_int_add (pos, v[i], 2, rptpos);
    rptpos[2] = 1;

    int skip = 0;
    for (j = 0; !skip && j < 2; j++)
      if (rptpos[j] < 1 || rptpos[j] > Tesr.size[j])
	skip = 1;

    if (skip)
      continue;

    if ((cell == NULL && cellqty == -1)
	|| (cell == NULL && cellqty == 0
	    && Tesr.VoxCell[rptpos[0]][rptpos[1]][1] != 0)
	|| ut_array_1d_int_eltpos (cell, cellqty,
				   Tesr.VoxCell[rptpos[0]][rptpos[1]][1])
	!= -1)
    {
      (*pqty)++;
      (*ppos) = ut_realloc_2d_int_addline (*ppos, *pqty, 3);
      ut_array_1d_int_memcpy ((*ppos)[(*pqty) - 1], 3, rptpos);
    }
  }

  ut_free_2d_int (v, vqty);
  ut_free_1d_int (rptpos);

  return;
}

void
neut_tesr_cell_tesrpos (struct TESR Tesr, int cell, int *prptqty, int ***prptpos)
{
  int i, j, k;

  (*prptqty) = 0;
  (*prptpos) = NULL;

  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)
	{
	  (*prptpos) =
	    ut_realloc_2d_int_addline ((*prptpos), ++(*prptqty), 3);
	  ut_array_1d_int_set_3 ((*prptpos)[(*prptqty) - 1], i, j, k);
	}

  return;
}

int
neut_tesr_renumber_continuous (struct TESR *pTesr)
{
  int i, j, k, l, idmax, oldidmax;
  int *qty = NULL;
  int CellQty_old = 0;
  int* CellId_old = NULL;
  int* CellId_old_inv = NULL;
  int CellId_old_max;
  double** CellOri_old = NULL;
  double** SeedCoo_old = NULL;
  double* SeedWeight_old = NULL;
  int* id_old_new = NULL;
  int id_old_max;

  if ((*pTesr).CellOri && !(*pTesr).CellId)
    ut_error_reportbug ();

  if ((*pTesr).CellId)
  {
    CellQty_old = (*pTesr).CellQty;
    CellId_old = ut_alloc_1d_int (CellQty_old + 1);
    ut_array_1d_int_memcpy (CellId_old + 1, CellQty_old,
                            (*pTesr).CellId + 1);
    ut_array_1d_int_inv (CellId_old + 1, CellQty_old, &CellId_old_inv,
						      &CellId_old_max);
    ut_array_1d_int_addval (CellId_old_inv, CellId_old_max, 1,
			    CellId_old_inv);
  }

  if ((*pTesr).CellOri)
  {
    CellOri_old = ut_alloc_2d (CellQty_old + 1, 4);
    ut_array_2d_memcpy (CellOri_old + 1, CellQty_old, 4,
                        (*pTesr).CellOri + 1);
  }

  if ((*pTesr).SeedCoo)
  {
    SeedCoo_old = ut_alloc_2d (CellQty_old + 1, 4);
    ut_array_2d_memcpy (SeedCoo_old + 1, CellQty_old, 4,
                        (*pTesr).SeedCoo + 1);
  }

  if ((*pTesr).SeedWeight)
  {
    SeedWeight_old = ut_alloc_1d (CellQty_old + 1);
    ut_array_1d_memcpy (SeedWeight_old + 1, CellQty_old,
                        (*pTesr).SeedWeight + 1);
  }

  idmax = 0;
  qty = ut_alloc_1d_int (1);
  for (k = 1; k <= (*pTesr).size[2]; k++)
    for (j = 1; j <= (*pTesr).size[1]; j++)
      for (i = 1; i <= (*pTesr).size[0]; i++)
      {
	if ((*pTesr).VoxCell[i][j][k] > idmax)
	{
	  oldidmax = idmax;
	  idmax = (*pTesr).VoxCell[i][j][k];
	  qty = ut_realloc_1d_int (qty, idmax + 1);
	  for (l = oldidmax + 1; l <= idmax; l++)
	    qty[l] = 0;
	}

	qty[(*pTesr).VoxCell[i][j][k]]++;
      }

  (*pTesr).CellQty = 0;
  (*pTesr).CellId = ut_alloc_1d_int (idmax + 1);
  for (i = 1; i <= idmax; i++)
    if (qty[i] > 0)
      (*pTesr).CellId[++(*pTesr).CellQty] = i;

  (*pTesr).CellId = ut_realloc_1d_int ((*pTesr).CellId,
				       (*pTesr).CellQty + 1);

  ut_array_1d_int_inv ((*pTesr).CellId, (*pTesr).CellQty + 1,
      &id_old_new, &id_old_max);

  for (k = 1; k <= (*pTesr).size[2]; k++)
    for (j = 1; j <= (*pTesr).size[1]; j++)
      for (i = 1; i <= (*pTesr).size[0]; i++)
	(*pTesr).VoxCell[i][j][k]
	  = id_old_new[(*pTesr).VoxCell[i][j][k]];

  if (CellQty_old > 0)
    for (i = 1; i <= (*pTesr).CellQty; i++)
      (*pTesr).CellId[i] = CellId_old[(*pTesr).CellId[i]];

  if (CellOri_old)
    for (i = 1; i <= (*pTesr).CellQty; i++)
      ut_array_1d_memcpy ((*pTesr).CellOri[i], 4,
	  CellOri_old[CellId_old_inv[(*pTesr).CellId[i]]]);

  if (SeedCoo_old)
    for (i = 1; i <= (*pTesr).CellQty; i++)
      ut_array_1d_memcpy ((*pTesr).SeedCoo[i], 4,
	  SeedCoo_old[CellId_old_inv[(*pTesr).CellId[i]]]);

  if (SeedWeight_old)
    for (i = 1; i <= (*pTesr).CellQty; i++)
      (*pTesr).SeedWeight[i] = SeedWeight_old[CellId_old_inv[(*pTesr).CellId[i]]];
  
  ut_free_1d_int (qty);
  ut_free_1d_int (id_old_new);
  ut_free_1d_int (CellId_old);
  ut_free_1d_int (CellId_old_inv);
  if (CellOri_old)
    ut_free_2d (CellOri_old, CellQty_old);
  if (SeedCoo_old)
    ut_free_2d (SeedCoo_old, CellQty_old);
  ut_free_1d (SeedWeight_old);

  return 0;
}

int
neut_tesr_cell_switch (struct TESR *pTesr, int cell1, int cell2)
{
  int i, j, k;

  for (k = 1; k <= (*pTesr).size[2]; k++)
    for (j = 1; j <= (*pTesr).size[1]; j++)
      for (i = 1; i <= (*pTesr).size[0]; i++)
	if ((*pTesr).VoxCell[i][j][k] == cell1)
	  (*pTesr).VoxCell[i][j][k] = cell2;
	else if ((*pTesr).VoxCell[i][j][k] == cell2)
	  (*pTesr).VoxCell[i][j][k] = cell1;

  if ((*pTesr).CellId)
    ut_array_1d_int_switch ((*pTesr).CellId, cell1, cell2);
  if ((*pTesr).CellOri)
    ut_array_2d_switchlines ((*pTesr).CellOri, 4, cell1, cell2);
  if ((*pTesr).SeedCoo)
    ut_array_2d_switchlines ((*pTesr).SeedCoo, 3, cell1, cell2);
  if ((*pTesr).SeedWeight)
    ut_array_1d_switch ((*pTesr).SeedWeight, cell1, cell2);

  return 0;
}

void
neut_tesr_init_tesrsize (struct TESR *pTesr, struct TESS Domain, int dim, char *rptstring)
{
  int i, qty, val;
  double avdsize;
  char **list = NULL;
  double **bbox = ut_alloc_2d (3, 2);

  neut_tess_bbox (Domain, bbox);

  ut_string_separate (rptstring, NEUT_SEP_DEP, &list, &qty);

  (*pTesr).Dim = dim;

  (*pTesr).size = ut_alloc_1d_int (3);
  ut_array_1d_int_set ((*pTesr).size, 3, 1);

  if (qty == 1)
  {
    ut_math_eval_int (list[0], 0, NULL, NULL, &val);

    if ((*pTesr).Dim == 1)
      avdsize = bbox[0][1];
    else if ((*pTesr).Dim == 2)
      avdsize = pow (bbox[0][1] * bbox[1][1], 0.5);
    else if ((*pTesr).Dim == 3)
      avdsize = pow (bbox[0][1] * bbox[1][1] * bbox[2][1], 0.3333333333333333);
    else
    {
      ut_error_reportbug ();
      abort ();
    }

    for (i = 0; i < (*pTesr).Dim; i++)
      (*pTesr).size[i] = ut_num_d2ri (val * bbox[i][1] / avdsize);
  }
  else if (qty == (*pTesr).Dim)
    for (i = 0; i < (*pTesr).Dim; i++)
      ut_math_eval_int (list[i], 0, NULL, NULL, &((*pTesr).size[i]));
  else
    abort ();

  (*pTesr).vsize = ut_alloc_1d (3);

  for (i = 0; i < (*pTesr).Dim; i++)
    (*pTesr).vsize[i] = bbox[i][1] / (*pTesr).size[i];

  ut_free_2d (bbox, 3);
  ut_free_2d_char (list, qty);

  return;
}

void
neut_tesr_crop (struct TESR *pTesr, char* shape)
{
  int i, j, status;
  double d;
  double* coo = ut_alloc_1d (3);
  double* coo2 = ut_alloc_1d (3);
  int* pt = ut_alloc_1d_int (3);

  if (!strncmp (shape, "cylinder(", 8))
  {
    status = sscanf (shape, "cylinder(%lf,%lf,%lf)", coo, coo + 1, &d);

    if (status != 3)
      ut_print_message (2, 2, "Unknown shape `%s'.\n", shape);

    for (j = 1; j <= (*pTesr).size[1]; j++)
      for (i = 1; i <= (*pTesr).size[0]; i++)
      {
	ut_array_1d_int_set_3 (pt, i, j, 1);
	neut_tesr_coo (*pTesr, pt, coo2);

	if (ut_space_dist2d (coo, coo2) > .5 * d)
	  ut_array_1d_int_set ((*pTesr).VoxCell[i][j] + 1, (*pTesr).size[2], 0);
      }
  }
  else
    ut_print_message (2, 2, "Unknown shape `%s'.\n", shape);

  ut_free_1d (coo);
  ut_free_1d (coo2);
  ut_free_1d_int (pt);

  return;
}
