/* 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_tess_op_.h"

void
neut_tess_set_zero (struct TESS *pTess)
{
  (*pTess).Dim = 0;

  (*pTess).Level = 0;
  (*pTess).TessId = 0;

  (*pTess).CellQty = 0;
  (*pTess).Type = NULL;

  (*pTess).VerQty = 0;
  (*pTess).FaceQty = 0;
  (*pTess).EdgeQty = 0;
  (*pTess).PolyQty = 0;
  (*pTess).VerCoo = NULL;
  (*pTess).VerEdgeQty = NULL;
  (*pTess).VerEdgeNb = NULL;
  (*pTess).VerDom = NULL;
  (*pTess).VerState = NULL;
  (*pTess).EdgeVerNb = NULL;
  (*pTess).EdgeFaceQty = NULL;
  (*pTess).EdgeFaceNb = NULL;
  (*pTess).EdgeLength = NULL;
  (*pTess).EdgeState = NULL;
  (*pTess).EdgeDel = NULL;
  (*pTess).EdgeDom = NULL;
  (*pTess).FacePoly = NULL;
  (*pTess).FaceVerQty = NULL;
  (*pTess).FaceVerNb = NULL;
  (*pTess).FaceEdgeNb = NULL;
  (*pTess).FaceEdgeOri = NULL;
  (*pTess).FaceEq = NULL;
  (*pTess).FaceState = NULL;
  (*pTess).FacePt = NULL;
  (*pTess).FacePtCoo = NULL;
  (*pTess).FaceDom = NULL;
  (*pTess).CellId = NULL;
  (*pTess).CellOri = NULL;
  (*pTess).PolyFaceQty = NULL;
  (*pTess).PolyFaceNb = NULL;
  (*pTess).PolyFaceOri = NULL;

  (*pTess).CellTrue = NULL;
  (*pTess).CellBody = NULL;
  (*pTess).SeedCoo = NULL;
  (*pTess).SeedWeight = NULL;

  (*pTess).DomType = NULL;

  (*pTess).DomVerQty = 0;
  (*pTess).DomVerCoo = NULL;
  (*pTess).DomVerLabel = NULL;
  (*pTess).DomVerEdgeQty = NULL;
  (*pTess).DomVerEdgeNb = NULL;
  (*pTess).DomTessVerNb = NULL;

  (*pTess).DomEdgeQty = 0;
  (*pTess).DomEdgeLabel = NULL;
  (*pTess).DomTessEdgeQty = NULL;
  (*pTess).DomEdgeVerNb = NULL;
  (*pTess).DomEdgeFaceNb = NULL;
  (*pTess).DomTessEdgeNb = NULL;

  (*pTess).DomFaceQty = 0;
  (*pTess).DomFaceLabel = NULL;
  (*pTess).DomFaceEq = NULL;
  (*pTess).DomFaceVerQty = NULL;
  (*pTess).DomFaceVerNb = NULL;
  (*pTess).DomFaceEdgeNb = NULL;
  (*pTess).DomTessFaceQty = NULL;
  (*pTess).DomTessFaceNb = NULL;

  (*pTess).ScaleQty = 0;
  (*pTess).ScaleCell = NULL;

  return;
}

void
neut_tess_alloc (struct TESS *pTess, int VerQty,
		 int EdgeQty, int FaceQty, int PolyQty)
{
  if (VerQty > 0)
  {
    (*pTess).VerQty = VerQty;
    (*pTess).VerCoo = ut_alloc_1d_pdouble ((*pTess).VerQty + 1);
    (*pTess).VerEdgeQty = ut_alloc_1d_int ((*pTess).VerQty + 1);
    (*pTess).VerEdgeNb = ut_alloc_1d_pint ((*pTess).VerQty + 1);
    (*pTess).VerDom = ut_alloc_1d_pint ((*pTess).VerQty + 1);
    (*pTess).VerState = ut_alloc_1d_int ((*pTess).VerQty + 1);
  }

  if (EdgeQty > 0)
  {
    (*pTess).EdgeQty = EdgeQty;
    (*pTess).EdgeVerNb = ut_alloc_1d_pint ((*pTess).EdgeQty + 1);
    (*pTess).EdgeFaceQty = ut_alloc_1d_int ((*pTess).EdgeQty + 1);
    (*pTess).EdgeFaceNb = ut_alloc_1d_pint ((*pTess).EdgeQty + 1);
    (*pTess).EdgeLength = ut_alloc_1d ((*pTess).EdgeQty + 1);
    (*pTess).EdgeState = ut_alloc_1d_int ((*pTess).EdgeQty + 1);
    (*pTess).EdgeDel = ut_alloc_1d_int ((*pTess).EdgeQty + 1);
    (*pTess).EdgeDom = ut_alloc_1d_pint ((*pTess).EdgeQty + 1);
  }

  if (FaceQty > 0)
  {
    (*pTess).FaceQty = FaceQty;
    (*pTess).FacePoly = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
    (*pTess).FaceEq = ut_alloc_1d_pdouble ((*pTess).FaceQty + 1);
    (*pTess).FaceVerQty = ut_alloc_1d_int ((*pTess).FaceQty + 1);
    (*pTess).FaceVerNb = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
    (*pTess).FaceEdgeNb = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
    (*pTess).FaceEdgeOri = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
    (*pTess).FaceState = ut_alloc_1d_int ((*pTess).FaceQty + 1);
    (*pTess).FacePt = ut_alloc_1d_int ((*pTess).FaceQty + 1);
    (*pTess).FacePtCoo = ut_alloc_1d_pdouble ((*pTess).FaceQty + 1);
    (*pTess).FaceDom = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
  }

  if (PolyQty > 0)
  {
    (*pTess).PolyQty = PolyQty;
    (*pTess).PolyFaceQty = ut_alloc_1d_int ((*pTess).PolyQty + 1);
    (*pTess).PolyFaceNb = ut_alloc_1d_pint ((*pTess).PolyQty + 1);
    (*pTess).PolyFaceOri = ut_alloc_1d_pint ((*pTess).PolyQty + 1);
  }

  return;
}

void
neut_tess_free (struct TESS *pTess)
{
  ut_free_2d ((*pTess).VerCoo, (*pTess).VerQty + 1);
  ut_free_1d_int ((*pTess).VerEdgeQty);
  ut_free_2d_int ((*pTess).VerEdgeNb, (*pTess).VerQty + 1);
  ut_free_2d_int ((*pTess).VerDom, (*pTess).VerQty + 1);
  ut_free_1d_int ((*pTess).VerState);

  ut_free_2d_int ((*pTess).EdgeVerNb, (*pTess).EdgeQty + 1);
  ut_free_1d_int ((*pTess).EdgeFaceQty);
  ut_free_2d_int ((*pTess).EdgeFaceNb, (*pTess).EdgeQty + 1);
  ut_free_1d ((*pTess).EdgeLength);
  ut_free_1d_int ((*pTess).EdgeState);
  ut_free_1d_int ((*pTess).EdgeDel);
  ut_free_2d_int ((*pTess).EdgeDom, (*pTess).EdgeQty + 1);

  if ((*pTess).Dim == 3)
    ut_free_2d_int ((*pTess).FacePoly, (*pTess).FaceQty + 1);

  ut_free_1d_int ((*pTess).FaceVerQty);
  ut_free_2d_int ((*pTess).FaceVerNb, (*pTess).FaceQty + 1);
  ut_free_2d_int ((*pTess).FaceEdgeNb, (*pTess).FaceQty + 1);
  ut_free_2d_int ((*pTess).FaceEdgeOri, (*pTess).FaceQty + 1);
  ut_free_2d ((*pTess).FaceEq, (*pTess).FaceQty + 1);
  ut_free_1d_int ((*pTess).FaceState);
  ut_free_1d_int ((*pTess).FacePt);
  ut_free_2d ((*pTess).FacePtCoo, (*pTess).FaceQty + 1);
  ut_free_2d_int ((*pTess).FaceDom, (*pTess).FaceQty + 1);

  ut_free_2d ((*pTess).SeedCoo, (*pTess).CellQty + 1);
  if ((*pTess).SeedWeight)
    ut_free_1d ((*pTess).SeedWeight);

  ut_free_1d_int ((*pTess).CellId);
  if ((*pTess).CellOri)
    ut_free_2d ((*pTess).CellOri, (*pTess).CellQty + 1);

  ut_free_1d_int ((*pTess).PolyFaceQty);
  ut_free_2d_int ((*pTess).PolyFaceNb, (*pTess).PolyQty + 1);
  ut_free_2d_int ((*pTess).PolyFaceOri, (*pTess).PolyQty + 1);

  ut_free_1d_int ((*pTess).CellTrue);
  ut_free_1d_int ((*pTess).CellBody);

  ut_free_1d_char ((*pTess).DomType);

  ut_free_2d ((*pTess).DomVerCoo, (*pTess).DomVerQty + 1);
  ut_free_2d_char ((*pTess).DomVerLabel, (*pTess).DomVerQty + 1);
  ut_free_1d_int ((*pTess).DomVerEdgeQty);
  ut_free_2d_int ((*pTess).DomVerEdgeNb, (*pTess).DomVerQty + 1);
  ut_free_1d_int ((*pTess).DomTessVerNb);

  ut_free_2d_char ((*pTess).DomEdgeLabel, (*pTess).DomEdgeQty + 1);
  ut_free_2d_int ((*pTess).DomEdgeVerNb, (*pTess).DomEdgeQty + 1);
  ut_free_2d_int ((*pTess).DomEdgeFaceNb, (*pTess).DomEdgeQty + 1);
  ut_free_1d_int ((*pTess).DomTessEdgeQty);
  ut_free_2d_int ((*pTess).DomTessEdgeNb, (*pTess).DomEdgeQty + 1);

  ut_free_2d_char ((*pTess).DomFaceLabel, (*pTess).DomFaceQty + 1);
  ut_free_2d ((*pTess).DomFaceEq, (*pTess).DomFaceQty + 1);
  ut_free_1d_int ((*pTess).DomFaceVerQty);
  ut_free_2d_int ((*pTess).DomFaceVerNb, (*pTess).DomFaceQty + 1);
  ut_free_2d_int ((*pTess).DomFaceEdgeNb, (*pTess).DomFaceQty + 1);
  ut_free_1d_int ((*pTess).DomTessFaceQty);
  ut_free_2d_int ((*pTess).DomTessFaceNb, (*pTess).DomFaceQty + 1);

  ut_free_1d_char ((*pTess).Type);

  if ((*pTess).ScaleCell)
    ut_free_2d_int ((*pTess).ScaleCell, (*pTess).ScaleQty);

  neut_tess_set_zero (pTess);

  return;
}


/* Deformation of the geoellation.
 */
void
neut_tess_scale (struct TESS *pTess, double vx, double vy, double vz)
{
  int i, j = 0, numa, numb;
  double norm;
  double *gsize = ut_alloc_1d (3);
  gsize[0] = vx;
  gsize[1] = vy;
  gsize[2] = vz;

  /* TODO alloc should probably not be done */
  (*pTess).EdgeLength =
    ut_realloc_1d ((*pTess).EdgeLength, (*pTess).EdgeQty + 1);

  /* changing vertex coordinates */
  for (i = 1; i <= (*pTess).VerQty; i++)
    for (j = 0; j < 3; j++)
      (*pTess).VerCoo[i][j] *= gsize[j];

  /* updating edge lengths from the ver positions */
  for (i = 1; i <= (*pTess).EdgeQty; i++)
  {
    numa = (*pTess).EdgeVerNb[i][0];
    numb = (*pTess).EdgeVerNb[i][1];

    (*pTess).EdgeLength[i] =
      ut_space_dist ((*pTess).VerCoo[numa], (*pTess).VerCoo[numb]);
  }

  /* updating face equations */
  for (i = 1; i <= (*pTess).FaceQty; i++)
  {
    (*pTess).FaceEq[i][1] /= gsize[0];
    (*pTess).FaceEq[i][2] /= gsize[1];
    (*pTess).FaceEq[i][3] /= gsize[2];
    norm = ut_vector_norm ((*pTess).FaceEq[i] + 1);
    for (j = 0; j < 4; j++)
      (*pTess).FaceEq[i][j] /= norm;
  }

  /* changing centre coordinates */
  for (i = 1; i <= (*pTess).PolyQty; i++)
    for (j = 0; j < 3; j++)
      (*pTess).SeedCoo[i][j] *= gsize[j];

  /* changing centre coordinates */
  for (i = 1; i <= (*pTess).FaceQty; i++)
    if ((*pTess).FaceState[i] > 0 && (*pTess).FacePt[i] == 0)
      for (j = 0; j < 3; j++)
	(*pTess).FacePtCoo[i][j] *= gsize[j];

  /* updating domain face equations */
  for (i = 1; i <= (*pTess).DomFaceQty; i++)
  {
    (*pTess).DomFaceEq[i][1] /= gsize[0];
    (*pTess).DomFaceEq[i][2] /= gsize[1];
    (*pTess).DomFaceEq[i][3] /= gsize[2];
    norm = ut_vector_norm ((*pTess).DomFaceEq[i] + 1);
    for (j = 0; j < 4; j++)
      (*pTess).DomFaceEq[i][j] /= norm;
  }

  ut_free_1d (gsize);

  return;
}


void
neut_tess_poly_switch (struct TESS *pTess, int p1, int p2)
{
  int i, id;

  if (p1 == p2)
    return;

  // SeedCoo
  ut_array_2d_switchlines ((*pTess).SeedCoo, 3, p1, p2);

  // SeedWeight
  if ((*pTess).SeedWeight)
    ut_array_1d_switch ((*pTess).SeedWeight, p1, p2);

  // CellTrue
  if ((*pTess).CellTrue != NULL)
    ut_array_1d_int_switch ((*pTess).CellTrue, p1, p2);

  // CellBody
  if ((*pTess).CellBody != NULL)
    ut_array_1d_int_switch ((*pTess).CellBody, p1, p2);

  // PolyFace* (keep FaceQty at the end)
  ut_array_2d_int_switchlines_length ((*pTess).PolyFaceNb,
				      p1, (*pTess).PolyFaceQty[p1] + 1,
				      p2, (*pTess).PolyFaceQty[p2] + 1);

  ut_array_2d_int_switchlines_length ((*pTess).PolyFaceOri,
				      p1, (*pTess).PolyFaceQty[p1] + 1,
				      p2, (*pTess).PolyFaceQty[p2] + 1);

  ut_array_1d_int_switch ((*pTess).PolyFaceQty, p1, p2);

  // FacePoly | the following is to avoid problems when p1 and p2 share
  // a com face
  for (i = 1; i <= (*pTess).PolyFaceQty[p1]; i++)
  {
    id = (*pTess).PolyFaceNb[p1][i];
    ut_array_1d_int_findnreplace ((*pTess).FacePoly[id], 2, p2, -1000);
  }
  for (i = 1; i <= (*pTess).PolyFaceQty[p2]; i++)
  {
    id = (*pTess).PolyFaceNb[p2][i];
    ut_array_1d_int_findnreplace ((*pTess).FacePoly[id], 2, p1, p2);
  }
  for (i = 1; i <= (*pTess).PolyFaceQty[p1]; i++)
  {
    id = (*pTess).PolyFaceNb[p1][i];
    ut_array_1d_int_findnreplace ((*pTess).FacePoly[id], 2, -1000, p1);
  }

  return;
}

void
neut_tess_init_edgelength (struct TESS *pTess)
{
  int i;

  (*pTess).EdgeLength =
    ut_realloc_1d ((*pTess).EdgeLength, (*pTess).EdgeQty + 1);

  for (i = 1; i <= (*pTess).EdgeQty; i++)
    neut_tess_init_edgelength_edge (pTess, i);

  return;
}

void
neut_tess_init_edgelength_edge (struct TESS *pTess, int edge)
{
  int ver1, ver2;

  ver1 = (*pTess).EdgeVerNb[edge][0];
  ver2 = (*pTess).EdgeVerNb[edge][1];

  (*pTess).EdgeLength[edge] = ut_space_dist ((*pTess).VerCoo[ver1],
					     (*pTess).VerCoo[ver2]);

  return;
}

void
neut_tess_init_polytopo_fromfacepoly (struct TESS *pTess)
{
  int i, j, poly;

  (*pTess).PolyQty = 0;
  for (i = 1; i <= (*pTess).FaceQty; i++)
    for (j = 0; j < 2; j++)
      (*pTess).PolyQty =
	ut_num_max ((*pTess).PolyQty, (*pTess).FacePoly[i][j]);

  (*pTess).PolyFaceQty = ut_alloc_1d_int ((*pTess).PolyQty + 1);
  (*pTess).PolyFaceNb = ut_alloc_2d_int ((*pTess).PolyQty + 1, 1);

  for (i = 1; i <= (*pTess).FaceQty; i++)
    for (j = 0; j < 2; j++)
      if ((*pTess).FacePoly[i][j] > 0)
      {
	poly = (*pTess).FacePoly[i][j];

	(*pTess).PolyFaceQty[poly]++;
	(*pTess).PolyFaceNb[poly] =
	  ut_realloc_1d_int ((*pTess).PolyFaceNb[poly],
			     (*pTess).PolyFaceQty[poly] + 1);
	(*pTess).PolyFaceNb[poly][(*pTess).PolyFaceQty[poly]] = i;
      }

  return;
}

void
neut_tess_init_edgetopo_fromver (struct TESS *pTess)
{
  int i, j, edge;

  (*pTess).EdgeVerNb = ut_alloc_2d_int ((*pTess).EdgeQty + 1, 2);

  for (i = 1; i <= (*pTess).VerQty; i++)
    for (j = 0; j < (*pTess).VerEdgeQty[i]; j++)
    {
      edge = (*pTess).VerEdgeNb[i][j];
      if (edge > 0)
      {
	if ((*pTess).EdgeVerNb[edge][0] == 0)
	  (*pTess).EdgeVerNb[edge][0] = i;
	else if ((*pTess).EdgeVerNb[edge][1] == 0)
	  (*pTess).EdgeVerNb[edge][1] = i;
	else
	  ut_error_reportbug ();
      }
    }

  return;
}

void
neut_tess_init_facetopo_fromedge (struct TESS *pTess)
{
  int i, j, face;

  (*pTess).FaceVerQty = ut_alloc_1d_int ((*pTess).FaceQty + 1);
  (*pTess).FaceEdgeNb = ut_alloc_2d_int ((*pTess).FaceQty + 1, 1);

  for (i = 1; i <= (*pTess).EdgeQty; i++)
    for (j = 0; j < (*pTess).EdgeFaceQty[i]; j++)
    {
      face = (*pTess).EdgeFaceNb[i][j];
      if (face > 0)
      {
	(*pTess).FaceVerQty[face]++;
	(*pTess).FaceEdgeNb[face] =
	  ut_realloc_1d_int ((*pTess).FaceEdgeNb[face],
			     (*pTess).FaceVerQty[face] + 1);
	(*pTess).FaceEdgeNb[face][(*pTess).FaceVerQty[face]] = i;
      }
    }

  // init FaceState
  (*pTess).FaceState =
    ut_realloc_1d_int ((*pTess).FaceState, (*pTess).FaceQty + 1);

  return;
}

void
neut_tess_init_facetopo_fromver (struct TESS *pTess)
{
  int i, j, k, edge, ver, pos;
  int *perm = NULL;

  // permuting FaceEdgeNb and init FaceEdgeOri & FaceVerNb
  (*pTess).FaceEdgeOri = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
  (*pTess).FaceVerNb = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
  for (i = 1; i <= (*pTess).FaceQty; i++)
  {
    perm = ut_alloc_1d_int ((*pTess).FaceVerQty[i] + 1);
    perm[1] = 1;
    edge = (*pTess).FaceEdgeNb[i][1];
    ver = (*pTess).EdgeVerNb[edge][1];
    // looking for the 2nd, 3rd,... edges
    for (j = 2; j <= (*pTess).FaceVerQty[i]; j++)
    {
      // checking every edges (we know it's not the 1st)
      for (k = 2; k <= (*pTess).FaceVerQty[i]; k++)
	if (k != perm[j - 1])
	{
	  edge = (*pTess).FaceEdgeNb[i][k];
	  pos = ut_array_1d_int_eltpos ((*pTess).EdgeVerNb[edge], 2, ver);
	  if (pos != -1)
	  {
	    perm[j] = k;
	    ver = (pos == 0) ? (*pTess).EdgeVerNb[edge][1]
	      : (*pTess).EdgeVerNb[edge][0];
	    break;
	  }
	}

      if (perm[j] == 0)
	ut_error_reportbug ();
    }

    ut_array_1d_permutation_int ((*pTess).FaceEdgeNb[i],
				 (*pTess).FaceVerQty[i] + 1, perm);

    ut_free_1d_int (perm);

    // init FaceEdgeOri and FaceVerNb
    (*pTess).FaceEdgeOri[i] = ut_alloc_1d_int ((*pTess).FaceVerQty[i] + 1);
    (*pTess).FaceVerNb[i] = ut_alloc_1d_int ((*pTess).FaceVerQty[i] + 1);

    edge = (*pTess).FaceEdgeNb[i][1];
    ver = (*pTess).EdgeVerNb[edge][1];
    (*pTess).FaceEdgeOri[i][1] = 1;
    (*pTess).FaceVerNb[i][1] = (*pTess).EdgeVerNb[edge][0];
    (*pTess).FaceVerNb[i][2] = (*pTess).EdgeVerNb[edge][1];

    for (j = 2; j <= (*pTess).FaceVerQty[i]; j++)
    {
      edge = (*pTess).FaceEdgeNb[i][j];
      if ((*pTess).EdgeVerNb[edge][0] == ver)
      {
	(*pTess).FaceEdgeOri[i][j] = 1;
	if (j < (*pTess).FaceVerQty[i])
	  (*pTess).FaceVerNb[i][j + 1] = (*pTess).EdgeVerNb[edge][1];
	ver = (*pTess).EdgeVerNb[edge][1];
      }
      else if ((*pTess).EdgeVerNb[edge][1] == ver)
      {
	(*pTess).FaceEdgeOri[i][j] = -1;
	if (j < (*pTess).FaceVerQty[i])
	  (*pTess).FaceVerNb[i][j + 1] = (*pTess).EdgeVerNb[edge][0];
	ver = (*pTess).EdgeVerNb[edge][0];
      }
      else
	ut_error_reportbug ();
    }
  }

  // reverse FaceVerNb and FaceEdgeNb and modify FaceEdgeOri
  for (i = 1; i <= (*pTess).FaceQty; i++)
    if (neut_tess_test_face_normal (*pTess, i, 0) != 0)
    {
      ut_array_1d_int_reverseelts ((*pTess).FaceEdgeNb[i] + 2,
				   (*pTess).FaceVerQty[i] - 1);
      ut_array_1d_int_reverseelts ((*pTess).FaceVerNb[i] + 2,
				   (*pTess).FaceVerQty[i] - 1);
      ut_array_1d_int_reverseelts ((*pTess).FaceEdgeOri[i] + 2,
				   (*pTess).FaceVerQty[i] - 1);
      ut_array_1d_int_scale ((*pTess).FaceEdgeOri[i] + 1,
			     (*pTess).FaceVerQty[i], -1);
    }

  // init FacePt, FacePtCoo
  (*pTess).FacePt = ut_alloc_1d_int ((*pTess).FaceQty + 1);
  ut_array_1d_int_set ((*pTess).FacePt + 1, (*pTess).FaceQty, -1);

  (*pTess).FacePtCoo = ut_alloc_2d ((*pTess).FaceQty + 1, 3);

  return;
}

double
neut_tess_face_ff (struct TESS Tess, int face)
{
  int j, k, ver1, ver2, ver3;
  double ff, thisff;
  double **eq = ut_alloc_2d (Tess.FaceVerQty[face] + 1, 4);

  if (Tess.FaceState[face] == 0)
    return 0;

  else if (Tess.FacePt[face] == 0)
  {
    ff = 0;
    for (j = 1; j <= Tess.FaceVerQty[face]; j++)
    {
      ver2 =
	Tess.FaceVerNb[face][ut_num_rotpos
				 (1, Tess.FaceVerQty[face],
				  j, 0)];
      ver3 =
	Tess.FaceVerNb[face][ut_num_rotpos
				 (1, Tess.FaceVerQty[face],
				  j, 1)];

      ut_space_points_plane (Tess.FacePtCoo[face], Tess.VerCoo[ver2],
			     Tess.VerCoo[ver3], eq[j]);
    }

    for (j = 1; j <= Tess.FaceVerQty[face]; j++)
      for (k = j + 1; k <= Tess.FaceVerQty[face]; k++)
      {
	thisff = ut_vector_angle (eq[j] + 1, eq[k] + 1);
	ff = ut_num_max (thisff, ff);
      }
  }

  else
  {
    ff = 0;

    /* ver i is the face point. */
    ver1 = Tess.FaceVerNb[face][Tess.FacePt[face]];

    for (j = 1; j <= Tess.FaceVerQty[face] - 2; j++)
    {
      ver2 =
	Tess.FaceVerNb[face][ut_num_rotpos
				 (1, Tess.FaceVerQty[face],
				  Tess.FacePt[face], j)];
      ver3 =
	Tess.FaceVerNb[face][ut_num_rotpos
				 (1, Tess.FaceVerQty[face],
				  Tess.FacePt[face], j + 1)];

      ut_space_points_plane (Tess.VerCoo[ver1], Tess.VerCoo[ver2],
			     Tess.VerCoo[ver3], eq[j]);
    }
    for (j = 1; j <= Tess.FaceVerQty[face] - 2; j++)
      for (k = j + 1; k <= Tess.FaceVerQty[face] - 2; k++)
      {
	thisff = ut_vector_angle (eq[j] + 1, eq[k] + 1);
	ff = ut_num_max (thisff, ff);
      }
  }

  ut_free_2d (eq, Tess.FaceVerQty[face] + 1);

  return ff;
}

void
neut_tess_init_celltrue (struct TESS *pTess)
{
  int i, j, all, cell, qty;
  int true, status;
  int** neighcell = NULL;
  int* neighcellqty = NULL;

  (*pTess).CellTrue = ut_realloc_1d_int ((*pTess).CellTrue, (*pTess).CellQty + 1);

  for (i = 1; i <= (*pTess).CellQty; i++)
    (*pTess).CellTrue[i] = neut_tess_cell_true (*pTess, i);

  neighcell = ut_alloc_1d_pint ((*pTess).CellQty + 1);
  neighcellqty = ut_alloc_1d_int ((*pTess).CellQty + 1);

  for (i = 1; i <= (*pTess).CellQty; i++)
    neut_tess_cell_neighcell (*pTess, i, &(neighcell[i]),
					 &(neighcellqty[i]));

  status = 1;
  for (true = 2; status == 1; true++)
  {
    status = 0;
    for (i = 1; i <= (*pTess).CellQty; i++)
    {
      if ((*pTess).Dim == 3)
	qty = (*pTess).PolyFaceQty[i];
      else if ((*pTess).Dim == 2)
	qty = (*pTess).FaceVerQty[i];
      else if ((*pTess).Dim == 1)
	qty = 2;
      else
	abort ();

      // if true is 1 lower and the cell has all neighbours
      if ((*pTess).CellTrue[i] == true - 1 && neighcellqty[i] == qty)
      {
	all = 1;
	for (j = 0; j < neighcellqty[i]; j++)
	{
	  cell = neighcell[i][j];

	  if ((*pTess).CellTrue[cell] < true - 1)
	  {
	    all = 0;
	    break;
	  }
	}
	if (all == 1)
	{
	  (*pTess).CellTrue[i] = true;
	  status = 1;
	}
      }
    }
  }

  ut_free_2d_int (neighcell, (*pTess).CellQty + 1);
  ut_free_1d_int (neighcellqty);

  return;
}

void
neut_tess_init_cellbody (struct TESS *pTess)
{
  int i, j, all, cell, qty;
  int body, status;
  int** neighcell = NULL;
  int* neighcellqty = NULL;

  (*pTess).CellBody = ut_realloc_1d_int ((*pTess).CellBody, (*pTess).CellQty + 1);

  for (i = 1; i <= (*pTess).CellQty; i++)
    (*pTess).CellBody[i] = neut_tess_cell_body (*pTess, i);

  neighcell = ut_alloc_1d_pint ((*pTess).CellQty + 1);
  neighcellqty = ut_alloc_1d_int ((*pTess).CellQty + 1);

  for (i = 1; i <= (*pTess).CellQty; i++)
    neut_tess_cell_neighcell (*pTess, i, &(neighcell[i]),
					 &(neighcellqty[i]));

  status = 1;
  for (body = 2; status == 1; body++)
  {
    status = 0;
    for (i = 1; i <= (*pTess).CellQty; i++)
    {
      if ((*pTess).Dim == 3)
	qty = (*pTess).PolyFaceQty[i];
      else if ((*pTess).Dim == 2)
	qty = (*pTess).FaceVerQty[i];
      else if ((*pTess).Dim == 1)
	qty = 2;
      else
	abort ();

      // if body is 1 lower and the cell has all neighbours
      if ((*pTess).CellBody[i] == body - 1 && neighcellqty[i] == qty)
      {
	all = 1;
	for (j = 0; j < neighcellqty[i]; j++)
	{
	  cell = neighcell[i][j];

	  if ((*pTess).CellBody[cell] < body - 1)
	  {
	    all = 0;
	    break;
	  }
	}
	if (all == 1)
	{
	  (*pTess).CellBody[i] = body;
	  status = 1;
	}
      }
    }
  }

  ut_free_2d_int (neighcell, (*pTess).CellQty + 1);
  ut_free_1d_int (neighcellqty);

  return;
}

// This function should only be used if the domain is not known
// (reconstruction from a mesh or a tess <= 1.9.2).
// Otherwise, use neut_tess_init_domain_poly.
void
neut_tess_init_domain (struct TESS *pTess)
{
  if ((*pTess).Dim == 3)
    neut_tess_init_domain_3d (pTess);
  else if ((*pTess).Dim == 2)
    neut_tess_init_domain_2d (pTess);
  else if ((*pTess).Dim == 1)
    neut_tess_init_domain_1d (pTess);
  else
    ut_error_reportbug ();

  return;
}

void
neut_tess_init_domain_3d (struct TESS *pTess)
{
  int i, j, k, ver, domver, domedge, face, poly, faceori;
  int *domface_edgeqty = NULL;
  int **domface_edges = NULL;
  int *domedge_verqty = NULL;
  int **domedge_vers = NULL;
  int interqty;
  int *inter = NULL;

  // Init FaceDom, DomFaceQty, DomFaceEq, DomTessFaceQty and DomTessFaceNb
  (*pTess).DomFaceQty = neut_tess_init_facedom_fromfacepoly (pTess);

  neut_tess_init_domtessface (pTess);

  (*pTess).DomFaceEq = ut_alloc_2d ((*pTess).DomFaceQty + 1, 4);
  for (i = 1; i <= (*pTess).DomFaceQty; i++)
  {
    face = (*pTess).DomTessFaceNb[i][1];
    poly = ut_array_1d_int_max ((*pTess).FacePoly[face], 2);
    neut_tess_poly_face_ori (*pTess, poly, face, &faceori);
    ut_array_1d_memcpy ((*pTess).DomFaceEq[i], 4, (*pTess).FaceEq[face]);
    ut_array_1d_scale ((*pTess).DomFaceEq[i], 4, faceori);
  }

  // Init DomEdgeQty, DomEdgeFaceNb, DomTessEdgeQty, DomTessEdgeNb.
  domface_edges = ut_alloc_1d_pint ((*pTess).DomFaceQty + 1);
  domface_edgeqty = ut_alloc_1d_int ((*pTess).DomFaceQty + 1);

  for (i = 1; i <= (*pTess).DomFaceQty; i++)
    neut_tess_domface_edges ((*pTess), i, &(domface_edges[i]),
			     &(domface_edgeqty[i]));

  (*pTess).DomEdgeQty = 0;
  (*pTess).DomEdgeFaceNb = ut_alloc_1d_pint (1);
  (*pTess).DomTessEdgeNb = ut_alloc_1d_pint (1);
  for (i = 1; i <= (*pTess).DomFaceQty; i++)
    for (j = i + 1; j <= (*pTess).DomFaceQty; j++)
    {
      inter = ut_alloc_1d_int (domface_edgeqty[i]);

      ut_array_1d_int_inter (domface_edges[i], domface_edgeqty[i],
			     domface_edges[j], domface_edgeqty[j],
			     inter, &interqty);

      if (interqty > 0)		// means that the domain faces share a domain edge
      {
	(*pTess).DomEdgeQty++;
	domedge = (*pTess).DomEdgeQty;

	(*pTess).DomEdgeFaceNb =
	  ut_realloc_2d_int_addline ((*pTess).DomEdgeFaceNb,
				     (*pTess).DomEdgeQty + 1, 2);
	(*pTess).DomEdgeFaceNb[domedge][0] = i;
	(*pTess).DomEdgeFaceNb[domedge][1] = j;

	(*pTess).DomTessEdgeQty = ut_realloc_1d_int ((*pTess).DomTessEdgeQty,
						     (*pTess).DomEdgeQty + 1);
	(*pTess).DomTessEdgeNb =
	  ut_realloc_2d_int_addline ((*pTess).DomTessEdgeNb,
				     (*pTess).DomEdgeQty + 1, interqty + 1);

	(*pTess).DomTessEdgeQty[domedge] = interqty;
	ut_array_1d_int_memcpy ((*pTess).DomTessEdgeNb[domedge] + 1, interqty,
				inter);
      }

      ut_free_1d_int (inter);
    }

  // Init DomVerQty, DomVerEdgeQty, DomVerEdgeNb and DomTessVerNb
  domedge_vers = ut_alloc_1d_pint ((*pTess).DomEdgeQty + 1);
  domedge_verqty = ut_alloc_1d_int ((*pTess).DomEdgeQty + 1);

  for (i = 1; i <= (*pTess).DomEdgeQty; i++)
    neut_tess_domedge_ver ((*pTess), i, &(domedge_vers[i]),
			   &(domedge_verqty[i]));

  (*pTess).DomVerQty = 0;
  (*pTess).DomVerCoo = ut_alloc_1d_pdouble (1);
  (*pTess).DomVerEdgeNb = ut_alloc_1d_pint (1);
  (*pTess).DomTessVerNb = ut_alloc_1d_int (1);
  for (i = 1; i <= (*pTess).DomEdgeQty; i++)
    for (j = i + 1; j <= (*pTess).DomEdgeQty; j++)
    {
      inter = ut_alloc_1d_int (domedge_verqty[i]);

      ut_array_1d_int_inter (domedge_vers[i], domedge_verqty[i],
			     domedge_vers[j], domedge_verqty[j],
			     inter, &interqty);

      if (interqty < 0 || interqty > 2)
	ut_error_reportbug ();

      if (interqty == 1)	// means that the domain edges share a domain ver
      {
	ver = inter[0];
	domver =
	  ut_array_1d_int_eltpos ((*pTess).DomTessVerNb,
				  (*pTess).DomVerQty + 1, ver);

	if (domver == -1)
	{
	  domver = ++(*pTess).DomVerQty;

	  (*pTess).DomVerEdgeQty =
	    ut_realloc_1d_int ((*pTess).DomVerEdgeQty,
			       (*pTess).DomVerQty + 1);
	  (*pTess).DomVerEdgeQty[domver] = 2;

	  (*pTess).DomVerEdgeNb =
	    ut_realloc_2d_int_addline ((*pTess).DomVerEdgeNb,
				       (*pTess).DomVerQty + 1, 2);
	  (*pTess).DomVerEdgeNb[domver][0] = i;
	  (*pTess).DomVerEdgeNb[domver][1] = j;

	  (*pTess).DomTessVerNb = ut_realloc_1d_int ((*pTess).DomTessVerNb,
						     (*pTess).DomVerQty + 1);

	  (*pTess).DomTessVerNb[domver] = ver;

	  (*pTess).DomVerCoo =
	    ut_realloc_2d_addline ((*pTess).DomVerCoo,
				   (*pTess).DomVerQty + 1, 3);
	  ut_array_1d_memcpy ((*pTess).DomVerCoo[domver], 3,
			      (*pTess).VerCoo[ver]);
	}
	else
	{
	  int *tmpedge = ut_alloc_1d_int (2);
	  tmpedge[0] = i;
	  tmpedge[1] = j;

	  for (k = 0; k < 2; k++)
	    if (ut_array_1d_int_eltpos ((*pTess).DomVerEdgeNb[domver],
					(*pTess).DomVerEdgeQty[domver],
					tmpedge[k]) == -1)
	    {
	      (*pTess).DomVerEdgeQty[domver]++;

	      (*pTess).DomVerEdgeNb[domver]
		= ut_realloc_1d_int ((*pTess).DomVerEdgeNb[domver],
				     (*pTess).DomVerEdgeQty[domver]);

	      (*pTess).DomVerEdgeNb[domver][(*pTess).DomVerEdgeQty[domver] -
					    1] = tmpedge[k];
	    }

	  ut_free_1d_int (tmpedge);
	}
      }

      ut_free_1d_int (inter);
    }

  // Init DomEdgeVerNb
  neut_tess_init_domain_domedgevernb (pTess);

  // Init DomFaceVerQty, DomFaceEdgeNb and DomFaceVerNb
  (*pTess).DomFaceVerQty = ut_alloc_1d_int ((*pTess).DomFaceQty + 1);
  (*pTess).DomFaceEdgeNb = ut_alloc_1d_pint ((*pTess).DomFaceQty + 1);
  for (i = 1; i <= (*pTess).DomEdgeQty; i++)
    for (j = 0; j < 2; j++)
    {
      face = (*pTess).DomEdgeFaceNb[i][j];

      (*pTess).DomFaceVerQty[face]++;
      (*pTess).DomFaceEdgeNb[face]
	=
	ut_realloc_1d_int ((*pTess).DomFaceEdgeNb[face],
			   (*pTess).DomFaceVerQty[face] + 1);
      (*pTess).DomFaceEdgeNb[face][(*pTess).DomFaceVerQty[face]] = i;
    }

  (*pTess).DomFaceVerNb = ut_alloc_1d_pint ((*pTess).DomFaceQty + 1);
  for (i = 1; i <= (*pTess).DomFaceQty; i++)
  {
    int qty;
    int *id = NULL;
    neut_tess_domedges_domvers (*pTess, (*pTess).DomFaceEdgeNb[i] + 1,
				(*pTess).DomFaceVerQty[i], &id, &qty);

    if (qty != (*pTess).DomFaceVerQty[i])
      ut_error_reportbug ();

    (*pTess).DomFaceVerNb[i] =
      ut_alloc_1d_int ((*pTess).DomFaceVerQty[i] + 1);
    ut_array_1d_int_memcpy ((*pTess).DomFaceVerNb[i] + 1, qty, id);

    ut_free_1d_int (id);
  }

  neut_tess_init_edgedom_fromfacedom (pTess);
  neut_tess_init_verdom_fromfacedom (pTess);

  // Settings face labels
  neut_tess_init_domain_label (pTess);

  return;
}

void
neut_tess_init_domain_2d (struct TESS *pTess)
{
  int i, j, domver;
  int *domedge_verqty = NULL;
  int **domedge_vers = NULL;
  int interqty;
  int *inter = NULL;

  // Init EdgeDom, DomEdgeQty, DomEdgeEq, DomTessEdgeQty and DomTessEdgeNb
  (*pTess).DomEdgeQty = neut_tess_init_edgedom_fromedgeface (pTess);

  neut_tess_init_domtessedge (pTess);

  // Init DomVerQty, DomVerEdgeNb, DomTessVerQty, DomTessVerNb.
  domedge_vers = ut_alloc_1d_pint ((*pTess).DomEdgeQty + 1);
  domedge_verqty = ut_alloc_1d_int ((*pTess).DomEdgeQty + 1);

  for (i = 1; i <= (*pTess).DomEdgeQty; i++)
    neut_tess_domedge_vers ((*pTess), i, &(domedge_vers[i]),
			     &(domedge_verqty[i]));

  (*pTess).DomVerQty = 0;
  (*pTess).DomVerCoo = ut_alloc_1d_pdouble (1);
  (*pTess).DomVerEdgeNb = ut_alloc_1d_pint (1);
  (*pTess).DomTessVerNb = ut_alloc_1d_int (1);
  for (i = 1; i <= (*pTess).DomEdgeQty; i++)
    for (j = i + 1; j <= (*pTess).DomEdgeQty; j++)
    {
      inter = ut_alloc_1d_int (domedge_verqty[i]);

      ut_array_1d_int_inter (domedge_vers[i], domedge_verqty[i],
			     domedge_vers[j], domedge_verqty[j],
			     inter, &interqty);

      if (interqty > 0)		// means that the domain edges share a domain ver
      {
	if (interqty != 1)
	  ut_error_reportbug ();

	(*pTess).DomVerQty++;
	domver = (*pTess).DomVerQty;

	(*pTess).DomVerCoo =
	  ut_realloc_2d_addline ((*pTess).DomVerCoo, (*pTess).DomVerQty + 1, 3);
	(*pTess).DomVerEdgeQty =
	  ut_realloc_1d_int ((*pTess).DomVerEdgeQty, (*pTess).DomVerQty + 1);
	(*pTess).DomVerEdgeNb =
	  ut_realloc_2d_int_addline ((*pTess).DomVerEdgeNb,
				     (*pTess).DomVerQty + 1, 2);
	(*pTess).DomVerEdgeQty[domver]   = 2;
	(*pTess).DomVerEdgeNb[domver][0] = i;
	(*pTess).DomVerEdgeNb[domver][1] = j;

	(*pTess).DomTessVerNb = ut_realloc_1d_int
				((*pTess).DomTessVerNb, (*pTess).DomVerQty + 1);

	(*pTess).DomTessVerNb[domver] = inter[0];
	ut_array_1d_memcpy ((*pTess).DomVerCoo[domver], 3,
			    (*pTess).VerCoo[inter[0]]);
      }

      ut_free_1d_int (inter);
    }

  neut_tess_init_domain_domedgevernb (pTess);
  (*pTess).DomEdgeFaceNb = ut_alloc_2d_int ((*pTess).DomEdgeQty + 1, 2);

  neut_tess_init_edgedom_fromedgeface (pTess);

  neut_tess_init_verdom_fromedgedom (pTess);

  // Settings face labels
  neut_tess_init_domain_label (pTess);

  return;
}

void
neut_tess_init_domain_1d (struct TESS *pTess)
{
  int i, ver;

  (*pTess).DomVerQty = neut_tess_init_verdom_fromveredge (pTess);
  (*pTess).DomVerEdgeQty = ut_alloc_1d_int ((*pTess).DomVerQty + 1);
  (*pTess).DomVerCoo = ut_alloc_2d ((*pTess).DomVerQty + 1, 3);

  neut_tess_init_domtessver (pTess);

  for (i = 1; i <= (*pTess).DomVerQty; i++)
  {
    ver = (*pTess).DomTessVerNb[i];
    ut_array_1d_memcpy ((*pTess).DomVerCoo[i], 3, (*pTess).VerCoo[ver]);
  }

  // Settings labels
  neut_tess_init_domain_label (pTess);

  return;
}

void
neut_tess_init_domain_poly (struct TESS *pTess, struct TESS Tess,
			    int poly, int **pVerNb, int **pEdgeNb,
			    int **pFaceNb)
{
  struct TESS DomTess;
  int verqty, edgeqty;
  int* vers = NULL, *edges = NULL;

  neut_tess_set_zero (&DomTess);

  neut_tess_poly_tess (Tess, poly, &DomTess);

  if (pVerNb)
  {
    neut_tess_poly_vers (Tess, poly, &vers, &verqty);
    (*pVerNb) = ut_alloc_1d_int (verqty + 1);
    ut_array_1d_int_memcpy ((*pVerNb) + 1, verqty, vers);
  }

  if (pEdgeNb)
  {
    neut_tess_poly_edges (Tess, poly, &edges, &edgeqty);
    (*pEdgeNb) = ut_alloc_1d_int (edgeqty + 1);
    ut_array_1d_int_memcpy ((*pEdgeNb) + 1, edgeqty, edges);
  }

  if (pFaceNb)
  {
    (*pFaceNb) = ut_alloc_1d_int (Tess.PolyFaceQty[poly] + 1);
    ut_array_1d_int_memcpy ((*pFaceNb) + 1, Tess.PolyFaceQty[poly],
			    Tess.PolyFaceNb[poly] + 1);
  }

  // Copying domain to the TESS
  neut_tess_init_domain_memcpy (pTess, DomTess);

  // We are left with linking the Tess to the Domain

  neut_tess_init_facedom_fromfacepoly (pTess);
  neut_tess_init_edgedom_fromfacedom (pTess);
  neut_tess_init_verdom_fromfacedom (pTess);

  neut_tess_init_domtessface (pTess);
  neut_tess_init_domtessedge (pTess);
  neut_tess_init_domtessver (pTess);

  neut_tess_free (&DomTess);
  ut_free_1d_int (vers);
  ut_free_1d_int (edges);

  return;
}

void
neut_tess_init_domtessface (struct TESS *pTess)
{
  int i, id;

  ut_free_1d_int ((*pTess).DomTessFaceQty);
  ut_free_2d_int ((*pTess).DomTessFaceNb, (*pTess).DomFaceQty + 1);

  (*pTess).DomTessFaceQty = ut_alloc_1d_int ((*pTess).DomFaceQty + 1);
  (*pTess).DomTessFaceNb = ut_alloc_1d_pint ((*pTess).DomFaceQty + 1);

  for (i = 1; i <= (*pTess).FaceQty; i++)
    if ((*pTess).FaceDom[i][0] == 2)
    {
      id = (*pTess).FaceDom[i][1];
      (*pTess).DomTessFaceQty[id]++;
      (*pTess).DomTessFaceNb[id] =
	ut_realloc_1d_int ((*pTess).DomTessFaceNb[id],
			   (*pTess).DomTessFaceQty[id] + 1);
      (*pTess).DomTessFaceNb[id][(*pTess).DomTessFaceQty[id]] = i;
    }

  return;
}

void
neut_tess_init_domtessedge (struct TESS *pTess)
{
  int i, id;

  ut_free_1d_int ((*pTess).DomTessEdgeQty);
  ut_free_2d_int ((*pTess).DomTessEdgeNb, (*pTess).DomEdgeQty + 1);

  (*pTess).DomTessEdgeQty = ut_alloc_1d_int ((*pTess).DomEdgeQty + 1);
  (*pTess).DomTessEdgeNb = ut_alloc_1d_pint ((*pTess).DomEdgeQty + 1);

  for (i = 1; i <= (*pTess).EdgeQty; i++)
    if ((*pTess).EdgeDom[i][0] == 1)
    {
      id = (*pTess).EdgeDom[i][1];
      (*pTess).DomTessEdgeQty[id]++;
      (*pTess).DomTessEdgeNb[id] =
	ut_realloc_1d_int ((*pTess).DomTessEdgeNb[id],
			   (*pTess).DomTessEdgeQty[id] + 1);
      (*pTess).DomTessEdgeNb[id][(*pTess).DomTessEdgeQty[id]] = i;
    }

  return;
}

void
neut_tess_init_domtessver (struct TESS *pTess)
{
  int i;
  int *nb = NULL;

  ut_free_1d_int ((*pTess).DomTessVerNb);

  (*pTess).DomTessVerNb = ut_alloc_1d_int ((*pTess).DomVerQty + 1);

  for (i = 1; i <= (*pTess).VerQty; i++)
    if ((*pTess).VerDom[i][0] == 0)
      (*pTess).DomTessVerNb[(*pTess).VerDom[i][1]] = i;

  ut_free_1d_int (nb);

  return;
}

void
neut_tess_init_verdom (struct TESS* pTess)
{
  int i, ver;

  (*pTess).VerDom = ut_alloc_2d_int ((*pTess).VerQty + 1, 2);
  ut_array_2d_int_set ((*pTess).VerDom + 1, (*pTess).VerQty, 1, -1);

  for (i = 1; i <= (*pTess).DomVerQty; i++)
  {
    ver = (*pTess).DomTessVerNb[i];
    (*pTess).VerDom[ver][0] = 0;
    (*pTess).VerDom[ver][1] = i;
  }

  return;
}

void
neut_tess_init_edgedom (struct TESS* pTess)
{
  int i, j, edge;

  (*pTess).EdgeDom = ut_alloc_2d_int ((*pTess).EdgeQty + 1, 2);
  ut_array_2d_int_set ((*pTess).EdgeDom + 1, (*pTess).EdgeQty, 1, -1);

  for (i = 1; i <= (*pTess).DomEdgeQty; i++)
    for (j = 1; j <= (*pTess).DomTessEdgeQty[i]; j++)
    {
      edge = (*pTess).DomTessEdgeNb[i][j];
      (*pTess).EdgeDom[edge][0] = 1;
      (*pTess).EdgeDom[edge][1] = i;
    }

  return;
}

void
neut_tess_init_facedom (struct TESS* pTess)
{
  int i, j, face;

  (*pTess).FaceDom = ut_alloc_2d_int ((*pTess).FaceQty + 1, 2);
  ut_array_2d_int_set ((*pTess).FaceDom + 1, (*pTess).FaceQty, 1, -1);

  for (i = 1; i <= (*pTess).DomFaceQty; i++)
    for (j = 1; j <= (*pTess).DomTessFaceQty[i]; j++)
    {
      face = (*pTess).DomTessFaceNb[i][j];
      (*pTess).FaceDom[face][0] = 2;
      (*pTess).FaceDom[face][1] = i;
    }

  return;
}

int
neut_tess_init_facedom_fromfacepoly (struct TESS *pTess)
{
  int i, id, max = 0;

  // Init face bound
  (*pTess).FaceDom = ut_alloc_2d_int ((*pTess).FaceQty + 1, 2);
  for (i = 1; i <= (*pTess).FaceQty; i++)
    (*pTess).FaceDom[i][0] = -1;

  if ((*pTess).Dim > 2)
    for (i = 1; i <= (*pTess).FaceQty; i++)
    {
      id = -ut_array_1d_int_min ((*pTess).FacePoly[i], 2);

      if (id > 0)
      {
	(*pTess).FaceDom[i][0] = 2;
	(*pTess).FaceDom[i][1] = id;
	max = ut_num_max (max, id);
      }
    }

  return max;
}

int
neut_tess_init_alldom_fromdomtess (struct TESS *pTess)
{
  int i, j, k, ver, edge, face;

  if ((*pTess).VerDom)
    ut_free_2d_int ((*pTess).VerDom, (*pTess).VerQty + 1);
  if ((*pTess).EdgeDom)
    ut_free_2d_int ((*pTess).EdgeDom, (*pTess).EdgeQty + 1);
  if ((*pTess).FaceDom)
    ut_free_2d_int ((*pTess).FaceDom, (*pTess).FaceQty + 1);

  (*pTess).VerDom = ut_alloc_2d_int ((*pTess).VerQty + 1, 2);
  ut_array_2d_int_set ((*pTess).VerDom + 1, (*pTess).VerQty, 2, -1);
  (*pTess).EdgeDom = ut_alloc_2d_int ((*pTess).EdgeQty + 1, 2);
  ut_array_2d_int_set ((*pTess).EdgeDom + 1, (*pTess).EdgeQty, 2, -1);
  (*pTess).FaceDom = ut_alloc_2d_int ((*pTess).FaceQty + 1, 2);
  ut_array_2d_int_set ((*pTess).FaceDom + 1, (*pTess).FaceQty, 2, -1);

  for (i = 1; i <= (*pTess).DomFaceQty; i++)
    for (j = 1; j <= (*pTess).DomTessFaceQty[i]; j++)
    {
      face = (*pTess).DomTessFaceNb[i][j];

      // setting FaceDom
      (*pTess).FaceDom[face][0] = 2;
      (*pTess).FaceDom[face][1] = i;
      (*pTess).FacePoly[face][1] = -i;

      // setting EdgeDom
      for (k = 1; k <= (*pTess).FaceVerQty[face]; k++)
      {
	edge = (*pTess).FaceEdgeNb[face][k];
	(*pTess).EdgeDom[edge][0] = 2;
	(*pTess).EdgeDom[edge][1] = i;
      }

      // setting VerDom
      for (k = 1; k <= (*pTess).FaceVerQty[face]; k++)
      {
	ver = (*pTess).FaceVerNb[face][k];
	(*pTess).VerDom[ver][0] = 2;
	(*pTess).VerDom[ver][1] = i;
      }
    }

  for (i = 1; i <= (*pTess).DomEdgeQty; i++)
    for (j = 1; j <= (*pTess).DomTessEdgeQty[i]; j++)
    {
      edge = (*pTess).DomTessEdgeNb[i][j];

      // setting EdgeDom
      (*pTess).EdgeDom[edge][0] = 1;
      (*pTess).EdgeDom[edge][1] = i;

      // setting VerDom
      for (k = 0; k < 2; k++)
      {
	ver = (*pTess).EdgeVerNb[edge][k];
	(*pTess).VerDom[ver][0] = 1;
	(*pTess).VerDom[ver][1] = i;
      }
    }

  for (i = 1; i <= (*pTess).DomVerQty; i++)
  {
    ver = (*pTess).DomTessVerNb[i];

    (*pTess).VerDom[ver][0] = 0;
    (*pTess).VerDom[ver][1] = i;
  }

  return 0;
}

int
neut_tess_init_edgedom_fromfacedom (struct TESS *pTess)
{
  int qty, i, j, max, face, status;
  int *nb = NULL;

  (*pTess).EdgeDom = ut_alloc_2d_int ((*pTess).EdgeQty + 1, 2);
  for (i = 1; i <= (*pTess).EdgeQty; i++)
    (*pTess).EdgeDom[i][0] = -1;

  for (i = 1; i <= (*pTess).EdgeQty; i++)
  {
    nb = ut_alloc_1d_int ((*pTess).EdgeFaceQty[i]);

    qty = 0;
    for (j = 0; j < (*pTess).EdgeFaceQty[i]; j++)
    {
      face = (*pTess).EdgeFaceNb[i][j];

      if ((*pTess).FaceDom[face][0] == 2)
	nb[qty++] = (*pTess).FaceDom[face][1];
    }

    ut_array_1d_int_sort_uniq (nb, qty, &qty);

    if (qty == 0)		// the edge is not on the domain
      (*pTess).EdgeDom[i][0] = -1;
    else if (qty == 1)		// the edge is on a domain face
    {
      (*pTess).EdgeDom[i][0] = 2;
      (*pTess).EdgeDom[i][1] = nb[1];
    }
    else if (qty == 2)		// the edge is on a domain edge
    {
      (*pTess).EdgeDom[i][0] = 1;
      status =
	neut_tess_domfaces_comdomedge (*pTess, nb, 2,
				       &((*pTess).EdgeDom[i][1]));
      if (status == -1)
	ut_error_reportbug ();
    }
    else
      ut_error_reportbug ();

    ut_free_1d_int (nb);
  }

  max = 0;
  for (i = 1; i <= (*pTess).EdgeQty; i++)
    if ((*pTess).EdgeDom[i][0] == 1)
      max = ut_num_max (max, (*pTess).EdgeDom[i][1]);

  return max;
}

int
neut_tess_init_edgedom_fromedgeface (struct TESS *pTess)
{
  int i, id, max;

  (*pTess).EdgeDom = ut_alloc_2d_int ((*pTess).EdgeQty + 1, 2);
  for (i = 1; i <= (*pTess).EdgeQty; i++)
    (*pTess).EdgeDom[i][0] = -1;

  for (i = 1; i <= (*pTess).EdgeQty; i++)
  {
    id = -ut_array_1d_int_min ((*pTess).EdgeFaceNb[i],
			       (*pTess).EdgeFaceQty[i]);

    if (id > 0)
    {
      (*pTess).EdgeDom[i][0] = 1;
      (*pTess).EdgeDom[i][1] = id;
    }
  }

  max = 0;
  for (i = 1; i <= (*pTess).EdgeQty; i++)
    if ((*pTess).EdgeDom[i][0] == 1)
      max = ut_num_max (max, (*pTess).EdgeDom[i][1]);

  return max;
}

int
neut_tess_init_verdom_fromfacedom (struct TESS *pTess)
{
  int i, j, max = 0, verbosity = 0;
  int faceqty, domfaceqty;
  int *face = NULL;
  int *domface = NULL;

  (*pTess).VerDom = ut_alloc_2d_int ((*pTess).VerQty + 1, 2);
  for (i = 1; i <= (*pTess).VerQty; i++)
    (*pTess).VerDom[i][0] = -1;

  for (i = 1; i <= (*pTess).VerQty; i++)
  {
    neut_tess_ver_faces (*pTess, i, &face, &faceqty);

    if (verbosity)
    {
      printf ("ver_face = ");
      ut_array_1d_int_fprintf (stdout, face, faceqty, "%d");
    }

    domface = ut_alloc_1d_int (faceqty + 1);

    domfaceqty = 0;
    for (j = 0; j < faceqty; j++)
      if ((*pTess).FaceDom[face[j]][0] == 2)
	domface[domfaceqty++] = (*pTess).FaceDom[face[j]][1];

    if (verbosity)
    {
      printf ("ver_domface = ");
      ut_array_1d_int_fprintf (stdout, domface, domfaceqty, "%d");
    }

    ut_array_1d_int_sort_uniq (domface, domfaceqty, &domfaceqty);

    if (verbosity)
    {
      printf ("ver_domface = ");
      ut_array_1d_int_fprintf (stdout, domface, faceqty, "%d");
    }

    if (domfaceqty == 0)	// the ver is not on the domain
      (*pTess).VerDom[i][0] = -1;
    else if (domfaceqty == 1)	// the ver is on a domain face
    {
      (*pTess).VerDom[i][0] = 2;
      (*pTess).VerDom[i][1] = domface[0];
    }
    else if (domfaceqty == 2)	// the ver is on a domain edge
    {
      (*pTess).VerDom[i][0] = 1;
      if (neut_tess_domfaces_comdomedge
	  (*pTess, domface, domfaceqty, &((*pTess).VerDom[i][1])) != 0)
	ut_error_reportbug ();
    }
    else if (domfaceqty >= 3)	// the ver is on a domain ver
    {
      (*pTess).VerDom[i][0] = 0;
      if (neut_tess_domfaces_comdomver
	  (*pTess, domface, domfaceqty, &((*pTess).VerDom[i][1])) != 0)
	ut_error_reportbug ();
    }

    ut_free_1d_int (domface);
    ut_free_1d_int (face);
    face = NULL;
  }

  max = 0;
  for (i = 1; i <= (*pTess).VerQty; i++)
    if ((*pTess).VerDom[i][0] == 0)
      max = ut_num_max (max, (*pTess).VerDom[i][1]);

  return max;
}

int
neut_tess_init_verdom_fromedgedom (struct TESS *pTess)
{
  int i, j, max = 0;

  (*pTess).VerDom = ut_alloc_2d_int ((*pTess).VerQty + 1, 2);
  for (i = 1; i <= (*pTess).VerQty; i++)
    (*pTess).VerDom[i][0] = -1;

  for (i = 1; i <= (*pTess).VerQty; i++)
  {
    int domedgeqty;
    int* domedge = ut_alloc_1d_int ((*pTess).VerEdgeQty[i]);

    domedgeqty = 0;
    for (j = 0; j < (*pTess).VerEdgeQty[i]; j++)
    {
      int edge = (*pTess).VerEdgeNb[i][j];
      if ((*pTess).EdgeDom[edge][0] == 1)
	domedge[domedgeqty++] = (*pTess).EdgeDom[edge][1];
    }

    ut_array_1d_int_sort_uniq (domedge, domedgeqty, &domedgeqty);

    if (domedgeqty == 0)	// the ver is not on the domain
      (*pTess).VerDom[i][0] = -1;
    else if (domedgeqty == 1)	// the ver is on a domain edge
    {
      (*pTess).VerDom[i][0] = 1;
      (*pTess).VerDom[i][1] = domedge[0];
    }
    else if (domedgeqty >= 2)	// the ver is on a domain ver
    {
      (*pTess).VerDom[i][0] = 0;
      if (neut_tess_domedges_comdomver
	  (*pTess, domedge, domedgeqty, &((*pTess).VerDom[i][1])) != 0)
      {
        printf ("no common domver for domedges ");
	ut_array_1d_int_fprintf (stdout, domedge, domedgeqty, "%d");
	ut_error_reportbug ();
      }
    }

    ut_free_1d_int (domedge);
  }

  max = 0;
  for (i = 1; i <= (*pTess).VerQty; i++)
    if ((*pTess).VerDom[i][0] == 0)
      max = ut_num_max (max, (*pTess).VerDom[i][1]);

  return max;
}

int
neut_tess_init_verdom_fromveredge (struct TESS *pTess)
{
  int i, id, max = 0;

  (*pTess).VerDom = ut_alloc_2d_int ((*pTess).VerQty + 1, 2);
  for (i = 1; i <= (*pTess).VerQty; i++)
    (*pTess).VerDom[i][0] = -1;

  for (i = 1; i <= (*pTess).VerQty; i++)
  {
    id = -ut_array_1d_int_min ((*pTess).VerEdgeNb[i],
			       (*pTess).VerEdgeQty[i]);

    if (id > 0)
    {
      (*pTess).VerDom[i][0] = 0;
      (*pTess).VerDom[i][1] = id;
      max = ut_num_max (max, id);
    }
  }

  max = 0;
  for (i = 1; i <= (*pTess).VerQty; i++)
    if ((*pTess).VerDom[i][0] == 0)
      max = ut_num_max (max, (*pTess).VerDom[i][1]);

  return max;
}

void
neut_tess_init_facedom_face_v (struct TESS *pTess, int face)
{
  int i, ver, qty;
  int domfaceqty1, domfaceqty2;
  int *domface1 = NULL;
  int *domface2 = NULL;

  // default value
  (*pTess).FaceDom[face][0] = -1;

  // if a ver is not on the domain, the face is not on the domain
  for (i = 1; i <= (*pTess).FaceVerQty[face]; i++)
  {
    ver = (*pTess).FaceVerNb[face][i];

    if ((*pTess).VerDom[ver][0] == -1)
    {
      (*pTess).FaceDom[face][0] = -1;
      return;
    }
  }

  // for all of the face vertices
  domfaceqty1 = 0;
  for (i = 1; i <= (*pTess).FaceVerQty[face]; i++)
  {
    ver = (*pTess).FaceVerNb[face][i];

    int *tmp = NULL;
    if ((*pTess).VerDom[ver][0] == 0)
      neut_tess_domver_domface (*pTess, (*pTess).VerDom[ver][1], &tmp, &qty);
    else if ((*pTess).VerDom[ver][0] == 1)
    {
      qty = 2;
      tmp = ut_alloc_1d_int (qty);
      ut_array_1d_int_memcpy (tmp, 2,
			      (*pTess).DomEdgeFaceNb[(*pTess).
						     VerDom[ver][1]]);
    }
    else if ((*pTess).VerDom[ver][0] == 2)
    {
      qty = 1;
      tmp = ut_alloc_1d_int (qty);
      tmp[0] = (*pTess).VerDom[ver][1];
    }

    domface1 = ut_realloc_1d_int (domface1, domfaceqty1 + qty);
    ut_array_1d_int_memcpy (domface1 + domfaceqty1, qty, tmp);
    domfaceqty1 += qty;

    ut_free_1d_int (tmp);
  }

  domface2 = ut_alloc_1d_int (domfaceqty1);
  ut_array_1d_int_memcpy (domface2, domfaceqty1, domface1);
  ut_array_1d_int_sort_uniq (domface2, domfaceqty1, &domfaceqty2);
  domface2 = ut_realloc_1d_int (domface2, domfaceqty2);

  for (i = 0; i < domfaceqty2; i++)
  {
    qty = ut_array_1d_int_nbofthisval (domface1, domfaceqty1, domface2[i]);
    if (qty == (*pTess).FaceVerQty[face])
    {
      (*pTess).FaceDom[face][0] = 2;
      (*pTess).FaceDom[face][1] = domface2[i];
      break;
    }
  }

  ut_free_1d_int (domface1);
  ut_free_1d_int (domface2);

  return;
}

void
neut_tess_cat (struct TESS *pTessA, struct TESS TessB)
{
  int i;
  int VerQty0 = (*pTessA).VerQty;
  int EdgeQty0 = (*pTessA).EdgeQty;
  int FaceQty0 = (*pTessA).FaceQty;
  int PolyQty0 = (*pTessA).PolyQty;

  // Adding vertices
  (*pTessA).VerQty += TessB.VerQty;
  (*pTessA).VerCoo
    = ut_realloc_1d_pdouble ((*pTessA).VerCoo, (*pTessA).VerQty + 1);

  (*pTessA).VerState
    = ut_realloc_1d_int ((*pTessA).VerState, (*pTessA).VerQty + 1);
  // neut_debug_tess (stdout, TessB);
  for (i = 1; i <= TessB.VerQty; i++)
  {
    (*pTessA).VerState[VerQty0 + i] = 0;
    (*pTessA).VerCoo[VerQty0 + i] = ut_alloc_1d (3);
    ut_array_1d_memcpy ((*pTessA).VerCoo[VerQty0 + i], 3, TessB.VerCoo[i]);
  }

  // Adding edges
  (*pTessA).EdgeQty += TessB.EdgeQty;
  (*pTessA).EdgeVerNb
    = ut_realloc_1d_pint ((*pTessA).EdgeVerNb, (*pTessA).EdgeQty + 1);
  (*pTessA).EdgeState
    = ut_realloc_1d_int ((*pTessA).EdgeState, (*pTessA).EdgeQty + 1);
  for (i = EdgeQty0 + 1; i <= (*pTessA).EdgeQty; i++)
  {
    (*pTessA).EdgeState[i] = 0;
    (*pTessA).EdgeVerNb[i] = ut_alloc_1d_int (2);
    ut_array_1d_int_memcpy
      ((*pTessA).EdgeVerNb[i], 2, TessB.EdgeVerNb[i - EdgeQty0]);
    ut_array_1d_int_addval ((*pTessA).EdgeVerNb[i], 2, VerQty0,
			    (*pTessA).EdgeVerNb[i]);
  }

  // Adding faces
  (*pTessA).FaceQty += TessB.FaceQty;
  (*pTessA).FaceState
    = ut_realloc_1d_int ((*pTessA).FaceState, (*pTessA).FaceQty + 1);
  (*pTessA).FaceVerQty
    = ut_realloc_1d_int ((*pTessA).FaceVerQty, (*pTessA).FaceQty + 1);
  for (i = 1; i <= TessB.FaceQty; i++)
  {
    (*pTessA).FaceState[i + FaceQty0] = 0;
    (*pTessA).FaceEdgeNb
      = ut_realloc_2d_int_addline ((*pTessA).FaceEdgeNb, FaceQty0 + i +
				   1, TessB.FaceVerQty[i] + 1);
    (*pTessA).FaceEdgeOri
      = ut_realloc_2d_int_addline ((*pTessA).FaceEdgeOri, FaceQty0 + i +
				   1, TessB.FaceVerQty[i] + 1);
    ut_array_1d_int_memcpy ((*pTessA).FaceEdgeNb[FaceQty0 + i] + 1,
			    TessB.FaceVerQty[i], TessB.FaceEdgeNb[i] + 1);
    ut_array_1d_int_memcpy ((*pTessA).FaceEdgeOri[FaceQty0 + i] + 1,
			    TessB.FaceVerQty[i], TessB.FaceEdgeOri[i] + 1);
    ut_array_1d_int_addval ((*pTessA).FaceEdgeNb[FaceQty0 + i] + 1,
			    TessB.FaceVerQty[i], EdgeQty0,
			    (*pTessA).FaceEdgeNb[FaceQty0 + i] + 1);

    (*pTessA).FaceVerQty[i + FaceQty0] = TessB.FaceVerQty[i];
  }

  // Adding polys
  (*pTessA).PolyQty += TessB.PolyQty;
  (*pTessA).PolyFaceQty
    = ut_realloc_1d_int ((*pTessA).PolyFaceQty, (*pTessA).PolyQty + 1);
  for (i = 1; i <= TessB.PolyQty; i++)
  {
    (*pTessA).PolyFaceNb
      = ut_realloc_2d_int_addline ((*pTessA).PolyFaceNb, PolyQty0 + i +
				   1, TessB.PolyFaceQty[i] + 1);
    (*pTessA).PolyFaceOri
      = ut_realloc_2d_int_addline ((*pTessA).PolyFaceOri, PolyQty0 + i +
				   1, TessB.PolyFaceQty[i] + 1);
    ut_array_1d_int_memcpy ((*pTessA).PolyFaceOri[PolyQty0 + i] + 1,
			    TessB.PolyFaceQty[i], TessB.PolyFaceOri[i] + 1);
    ut_array_1d_int_memcpy ((*pTessA).PolyFaceNb[PolyQty0 + i] + 1,
			    TessB.PolyFaceQty[i], TessB.PolyFaceNb[i] + 1);
    ut_array_1d_int_addval ((*pTessA).PolyFaceNb[PolyQty0 + i] + 1,
			    TessB.PolyFaceQty[i], FaceQty0,
			    (*pTessA).PolyFaceNb[PolyQty0 + i] + 1);

    (*pTessA).PolyFaceQty[i + PolyQty0] = TessB.PolyFaceQty[i];
  }

  return;
}


void
neut_tess_poly_tess (struct TESS Tess, int poly, struct TESS *pTess)
{
  int i, j, ver, edge, face;
  int *VerNb_old_new = NULL;
  int VerNb_old_max;
  int *EdgeNb_old_new = NULL;
  int EdgeNb_old_max;
  int *FaceNb_old_new = NULL;
  int FaceNb_old_max;
  int* PolyVerNb = NULL;
  int PolyVerQty;
  int* PolyEdgeNb = NULL;
  int PolyEdgeQty;

  neut_tess_poly_vers (Tess, poly, &PolyVerNb, &PolyVerQty);
  neut_tess_poly_edges (Tess, poly, &PolyEdgeNb, &PolyEdgeQty);

  // General information
  (*pTess).Dim = Tess.Dim;
  (*pTess).Level = Tess.Level;
  (*pTess).TessId = Tess.TessId;
  (*pTess).CellQty = 1;

  if (Tess.Type)
    ut_string_string (Tess.Type, &((*pTess).Type));

  ut_array_1d_int_inv (PolyVerNb, PolyVerQty,
		       &VerNb_old_new, &VerNb_old_max);
  ut_array_1d_int_addval (VerNb_old_new, VerNb_old_max, 1, VerNb_old_new);

  ut_array_1d_int_inv (PolyEdgeNb, PolyEdgeQty,
		       &EdgeNb_old_new, &EdgeNb_old_max);
  ut_array_1d_int_addval (EdgeNb_old_new, EdgeNb_old_max, 1, EdgeNb_old_new);

  ut_array_1d_int_inv (Tess.PolyFaceNb[poly] + 1, Tess.PolyFaceQty[poly],
		       &FaceNb_old_new, &FaceNb_old_max);
  ut_array_1d_int_addval (FaceNb_old_new, FaceNb_old_max, 1, FaceNb_old_new);
  FaceNb_old_max--;

  // Poly ------------

  (*pTess).PolyQty = 1;
  (*pTess).SeedCoo = ut_alloc_2d (2, 3);
  ut_array_1d_memcpy ((*pTess).SeedCoo[1], 3, Tess.SeedCoo[poly]);

  if (Tess.SeedWeight)
  {
    (*pTess).SeedWeight = ut_alloc_1d (2);
    (*pTess).SeedWeight[1] = Tess.SeedWeight[poly];
  }

  (*pTess).CellTrue = ut_alloc_1d_int (2);
  (*pTess).CellBody = ut_alloc_1d_int (2);

  (*pTess).PolyFaceQty = ut_alloc_1d_int (2);
  (*pTess).PolyFaceNb = ut_alloc_1d_pint (2);
  (*pTess).PolyFaceOri = ut_alloc_1d_pint (2);
  (*pTess).PolyFaceQty[1] = Tess.PolyFaceQty[poly];
  (*pTess).PolyFaceNb[1] = ut_alloc_1d_int ((*pTess).PolyFaceQty[1] + 1);
  (*pTess).PolyFaceOri[1] = ut_alloc_1d_int ((*pTess).PolyFaceQty[1] + 1);
  for (j = 1; j <= (*pTess).PolyFaceQty[1]; j++)
  {
    (*pTess).PolyFaceNb[1][j] = FaceNb_old_new[Tess.PolyFaceNb[poly][j]];
    (*pTess).PolyFaceOri[1][j] = Tess.PolyFaceOri[poly][j];
  }

  // Faces ------------

  (*pTess).FaceQty = Tess.PolyFaceQty[poly];
  (*pTess).FacePoly = ut_alloc_2d_int ((*pTess).FaceQty + 1, 2);
  (*pTess).FaceEq = ut_alloc_2d ((*pTess).FaceQty + 1, 4);
  (*pTess).FaceState = ut_alloc_1d_int ((*pTess).FaceQty + 1);
  (*pTess).FacePt = ut_alloc_1d_int ((*pTess).FaceQty + 1);
  (*pTess).FacePtCoo = ut_alloc_2d ((*pTess).FaceQty + 1, 3);
  (*pTess).FaceVerQty = ut_alloc_1d_int ((*pTess).FaceQty + 1);
  (*pTess).FaceVerNb = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
  (*pTess).FaceEdgeNb = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
  (*pTess).FaceEdgeOri = ut_alloc_1d_pint ((*pTess).FaceQty + 1);
  (*pTess).FaceDom = ut_alloc_2d_int ((*pTess).FaceQty + 1, 2);

  for (i = 1; i <= (*pTess).FaceQty; i++)
    (*pTess).FaceDom[i][0] = -1;

  for (i = 1; i <= (*pTess).FaceQty; i++)
  {
    face = Tess.PolyFaceNb[poly][i];
    ut_array_1d_memcpy ((*pTess).FaceEq[i], 4, Tess.FaceEq[face]);

    (*pTess).FacePoly[i][0] = 1;
    (*pTess).FacePoly[i][1] = -i;	// here, loosing link with real neighbours

    (*pTess).FaceVerQty[i] = Tess.FaceVerQty[face];
    (*pTess).FaceVerNb[i] = ut_alloc_1d_int ((*pTess).FaceVerQty[i] + 1);
    for (j = 1; j <= (*pTess).FaceVerQty[i]; j++)
      (*pTess).FaceVerNb[i][j] = VerNb_old_new[Tess.FaceVerNb[face][j]];

    (*pTess).FaceEdgeNb[i] = ut_alloc_1d_int ((*pTess).FaceVerQty[i] + 1);
    (*pTess).FaceEdgeOri[i] = ut_alloc_1d_int ((*pTess).FaceVerQty[i] + 1);
    for (j = 1; j <= (*pTess).FaceVerQty[i]; j++)
    {
      (*pTess).FaceEdgeNb[i][j] = EdgeNb_old_new[Tess.FaceEdgeNb[face][j]];
      (*pTess).FaceEdgeOri[i][j] = Tess.FaceEdgeOri[face][j];
    }
  }

  // Edges ---------
  (*pTess).EdgeQty = PolyEdgeQty;
  (*pTess).EdgeVerNb = ut_alloc_2d_int ((*pTess).EdgeQty + 1, 2);
  (*pTess).EdgeLength = ut_alloc_1d ((*pTess).EdgeQty + 1);
  (*pTess).EdgeState = ut_alloc_1d_int ((*pTess).EdgeQty + 1);
  (*pTess).EdgeDel = ut_alloc_1d_int ((*pTess).EdgeQty + 1);
  (*pTess).EdgeDom = ut_alloc_2d_int ((*pTess).EdgeQty + 1, 2);

  for (i = 1; i <= (*pTess).EdgeQty; i++)
    (*pTess).EdgeDom[i][0] = -1;

  for (i = 1; i <= (*pTess).EdgeQty; i++)
  {
    edge = PolyEdgeNb[i - 1];
    for (j = 0; j < 2; j++)
    {
      (*pTess).EdgeVerNb[i][j] = VerNb_old_new[Tess.EdgeVerNb[edge][j]];
      if ((*pTess).EdgeVerNb[i][j] <= 0)
	abort ();
    }
    (*pTess).EdgeLength[i] = Tess.EdgeLength[edge];
  }

  // looping on the faces
  (*pTess).EdgeFaceQty = ut_alloc_1d_int ((*pTess).EdgeQty + 1);
  (*pTess).EdgeFaceNb = ut_alloc_1d_pint ((*pTess).EdgeQty + 1);
  for (i = 1; i <= (*pTess).FaceQty; i++)
    for (j = 1; j <= (*pTess).FaceVerQty[i]; j++)
    {
      edge = (*pTess).FaceEdgeNb[i][j];
      (*pTess).EdgeFaceQty[edge]++;
      (*pTess).EdgeFaceNb[edge]
	= ut_realloc_1d_int ((*pTess).EdgeFaceNb[edge],
			     (*pTess).EdgeFaceQty[edge]);
      (*pTess).EdgeFaceNb[edge][(*pTess).EdgeFaceQty[edge] - 1] = i;
    }

  // Vertices ---------
  (*pTess).VerQty = PolyVerQty;
  (*pTess).VerCoo = ut_alloc_2d ((*pTess).VerQty + 1, 3);
  (*pTess).VerState = ut_alloc_1d_int ((*pTess).VerQty + 1);
  (*pTess).VerDom = ut_alloc_2d_int ((*pTess).VerQty + 1, 2);

  for (i = 1; i <= (*pTess).VerQty; i++)
  {
    ver = PolyVerNb[i - 1];
    ut_array_1d_memcpy ((*pTess).VerCoo[i], 3, Tess.VerCoo[ver]);
  }

  for (i = 1; i <= (*pTess).VerQty; i++)
    (*pTess).VerDom[i][0] = -1;

  // looping on the edges
  (*pTess).VerEdgeQty = ut_alloc_1d_int ((*pTess).VerQty + 1);
  (*pTess).VerEdgeNb = ut_alloc_1d_pint ((*pTess).VerQty + 1);
  for (i = 1; i <= (*pTess).EdgeQty; i++)
    for (j = 0; j < 2; j++)
    {
      ver = (*pTess).EdgeVerNb[i][j];
      (*pTess).VerEdgeQty[ver]++;
      (*pTess).VerEdgeNb[ver]
	= ut_realloc_1d_int ((*pTess).VerEdgeNb[ver],
			     (*pTess).VerEdgeQty[ver]);
      (*pTess).VerEdgeNb[ver][(*pTess).VerEdgeQty[ver] - 1] = i;
    }

  // Domain
  if (Tess.PolyQty == 1)
  {
    (*pTess).DomType = ut_alloc_1d_char (strlen (Tess.DomType) + 1);
    strcpy ((*pTess).DomType, Tess.DomType);
  }
  else
  {
    (*pTess).DomType = ut_alloc_1d_char (5);
    strcpy ((*pTess).DomType, "poly");
  }

  ut_free_1d_int (VerNb_old_new);
  ut_free_1d_int (EdgeNb_old_new);
  ut_free_1d_int (FaceNb_old_new);
  ut_free_1d_int (PolyVerNb);
  ut_free_1d_int (PolyEdgeNb);

  return;
}

/*
void
neut_tess_poly_tess (struct TESS Tess, int poly, struct TESS* pPTess)
{
  struct POLY P;
  neut_poly_set_zero (&P);

  net_tess_poly (Tess, poly, &P);
  net_poly_tess (P, pPTess);

  if (Tess.PolyQty == 1)
  {
    (*pPTess).DomType = ut_alloc_1d_char (strlen (Tess.DomType) + 1);
    strcpy ((*pPTess).DomType, Tess.DomType);
  }
  else
  {
    (*pPTess).DomType = ut_alloc_1d_char (5);
    strcpy ((*pPTess).DomType, "poly");
  }

  neut_poly_free (&P);

  return;
}
*/

int
neut_tess_addver (struct TESS *pTess, double *coo)
{
  (*pTess).VerQty++;
  (*pTess).VerCoo
    = ut_realloc_2d_addline ((*pTess).VerCoo, (*pTess).VerQty + 1, 3);
  ut_array_1d_memcpy ((*pTess).VerCoo[(*pTess).VerQty], 3, coo);

  (*pTess).VerEdgeQty = ut_realloc_1d_int ((*pTess).VerEdgeQty,
					   (*pTess).VerQty + 1);
  (*pTess).VerEdgeQty[(*pTess).VerQty] = 0;

  (*pTess).VerEdgeNb = ut_realloc_1d_pint ((*pTess).VerEdgeNb,
					   (*pTess).VerQty + 1);
  (*pTess).VerEdgeNb[0] = NULL;
  (*pTess).VerEdgeNb[(*pTess).VerQty] = NULL;

  (*pTess).VerDom
    = ut_realloc_2d_int_addline ((*pTess).VerDom, (*pTess).VerQty + 1, 2);
  (*pTess).VerDom[0] = NULL;

  (*pTess).VerState = ut_realloc_1d_int ((*pTess).VerState,
					 (*pTess).VerQty + 1);
  (*pTess).VerState[(*pTess).VerQty] = 0;

  return (*pTess).VerQty;
}

int
neut_tess_addedge (struct TESS *pTess, int ver1, int ver2)
{
  (*pTess).EdgeQty++;
  (*pTess).EdgeVerNb = ut_realloc_2d_int_addline ((*pTess).EdgeVerNb,
						  (*pTess).EdgeQty + 1, 2);
  (*pTess).EdgeVerNb[0] = NULL;

  ut_array_1d_int_set_2 ((*pTess).EdgeVerNb[(*pTess).EdgeQty], ver1, ver2);

  (*pTess).EdgeFaceQty
    = ut_realloc_1d_int ((*pTess).EdgeFaceQty, (*pTess).EdgeQty + 1);
  (*pTess).EdgeFaceQty[(*pTess).EdgeQty] = 0;

  (*pTess).EdgeFaceNb
    = ut_realloc_1d_pint ((*pTess).EdgeFaceNb, (*pTess).EdgeQty + 1);
  (*pTess).EdgeFaceNb[(*pTess).EdgeQty] = NULL;

  (*pTess).EdgeLength
    = ut_realloc_1d ((*pTess).EdgeLength, (*pTess).EdgeQty + 1);
  (*pTess).EdgeLength[(*pTess).EdgeQty]
    = ut_space_dist ((*pTess).VerCoo[ver1], (*pTess).VerCoo[ver2]);

  (*pTess).EdgeState
    = ut_realloc_1d_int ((*pTess).EdgeState, (*pTess).EdgeQty + 1);
  (*pTess).EdgeState[(*pTess).EdgeQty] = 0;

  (*pTess).EdgeDel
    = ut_realloc_1d_int ((*pTess).EdgeDel, (*pTess).EdgeQty + 1);
  (*pTess).EdgeDel[(*pTess).EdgeQty] = 0;

  (*pTess).EdgeDom
    = ut_realloc_2d_int_addline ((*pTess).EdgeDom, (*pTess).EdgeQty + 1, 2);
  (*pTess).EdgeDom[0] = NULL;

  return (*pTess).EdgeQty;
}

int
neut_tess_addface_alloc (struct TESS *pTess)
{
  int face = ++(*pTess).FaceQty;

  (*pTess).FaceEq
    = ut_realloc_2d_addline ((*pTess).FaceEq, (*pTess).FaceQty + 1, 4);
  (*pTess).FaceEq[0] = NULL;

  (*pTess).FaceVerQty = ut_realloc_1d_int ((*pTess).FaceVerQty,
					   (*pTess).FaceQty + 1);
  (*pTess).FaceVerQty[face] = 0;

  (*pTess).FaceEdgeNb
    = ut_realloc_1d_pint ((*pTess).FaceEdgeNb, (*pTess).FaceQty + 1);
  (*pTess).FaceEdgeNb[0] = NULL;
  (*pTess).FaceEdgeNb[face] = NULL;

  (*pTess).FaceEdgeOri
    = ut_realloc_1d_pint ((*pTess).FaceEdgeOri, (*pTess).FaceQty + 1);
  (*pTess).FaceEdgeOri[0] = NULL;
  (*pTess).FaceEdgeOri[face] = NULL;

  (*pTess).FaceVerNb
    = ut_realloc_1d_pint ((*pTess).FaceVerNb, (*pTess).FaceQty + 1);
  (*pTess).FaceVerNb[0] = NULL;
  (*pTess).FaceVerNb[face] = NULL;

  (*pTess).FaceState
    = ut_realloc_1d_int ((*pTess).FaceState, (*pTess).FaceQty + 1);
  (*pTess).FaceState[face] = 0;

  (*pTess).FacePt = ut_realloc_1d_int ((*pTess).FacePt, (*pTess).FaceQty + 1);
  (*pTess).FacePt[face] = 0;

  (*pTess).FacePtCoo
    = ut_realloc_2d_addline ((*pTess).FacePtCoo, (*pTess).FaceQty + 1, 3);
  (*pTess).FacePtCoo[0] = NULL;

  (*pTess).FaceDom
    = ut_realloc_2d_int_addline ((*pTess).FaceDom, (*pTess).FaceQty + 1, 2);
  (*pTess).FaceDom[0] = NULL;

  (*pTess).FacePoly
    = ut_realloc_2d_int_addline ((*pTess).FacePoly, (*pTess).FaceQty + 1, 2);
  (*pTess).FacePoly[0] = NULL;

  return face;
}

int
neut_tess_addpoly_alloc (struct TESS *pTess)
{
  int poly = ++(*pTess).PolyQty;

  (*pTess).PolyFaceQty = ut_realloc_1d_int ((*pTess).PolyFaceQty,
					    (*pTess).PolyQty + 1);
  (*pTess).PolyFaceQty[poly] = 0;

  (*pTess).PolyFaceNb
    = ut_realloc_1d_pint ((*pTess).PolyFaceNb, (*pTess).PolyQty + 1);
  (*pTess).PolyFaceNb[0] = NULL;
  (*pTess).PolyFaceNb[poly] = NULL;

  (*pTess).PolyFaceOri
    = ut_realloc_1d_pint ((*pTess).PolyFaceOri, (*pTess).PolyQty + 1);
  (*pTess).PolyFaceOri[0] = NULL;
  (*pTess).PolyFaceOri[poly] = NULL;

  return poly;
}

int
neut_tess_addcell_alloc (struct TESS *pTess)
{
  int cell = ++(*pTess).CellQty;

  (*pTess).CellId = ut_realloc_1d_int ((*pTess).CellId, (*pTess).CellQty + 1);
  (*pTess).CellId[0] = 0;
  (*pTess).CellId[cell] = cell;

  (*pTess).CellOri = ut_realloc_1d_pdouble ((*pTess).CellOri, (*pTess).CellQty + 1);
  (*pTess).CellOri[0] = NULL;
  (*pTess).CellOri[cell] = ut_alloc_1d (4);

  (*pTess).CellTrue = ut_realloc_1d_int ((*pTess).CellTrue, (*pTess).CellQty + 1);
  (*pTess).CellTrue[0] = 0;
  (*pTess).CellTrue[cell] = 0;

  (*pTess).CellBody = ut_realloc_1d_int ((*pTess).CellBody, (*pTess).CellQty + 1);
  (*pTess).CellBody[0] = 0;
  (*pTess).CellBody[cell] = 0;

  (*pTess).SeedCoo = ut_realloc_1d_pdouble ((*pTess).SeedCoo, (*pTess).CellQty + 1);
  (*pTess).SeedCoo[0] = NULL;
  (*pTess).SeedCoo[cell] = ut_alloc_1d (3);

  (*pTess).SeedWeight = ut_realloc_1d ((*pTess).SeedWeight, (*pTess).CellQty + 1);
  (*pTess).SeedWeight[0] = 0;
  (*pTess).SeedWeight[cell] = 0;

  return cell;
}

void
neut_tess_face_addedge (struct TESS *pTess, int face, int edge, int ori)
{
  int pos, edgeqty;

  if (edge < 0 || (ori != 1 && ori != -1))
    ut_error_reportbug ();

  edgeqty = ++(*pTess).FaceVerQty[face];
  (*pTess).FaceEdgeNb[face] = ut_realloc_1d_int ((*pTess).FaceEdgeNb[face],
						 edgeqty + 1);
  (*pTess).FaceEdgeOri[face] = ut_realloc_1d_int ((*pTess).FaceEdgeOri[face],
						  edgeqty + 1);

  (*pTess).FaceEdgeNb[face][edgeqty] = edge;
  (*pTess).FaceEdgeOri[face][edgeqty] = ori;

  (*pTess).FaceVerNb[face] = ut_realloc_1d_int ((*pTess).FaceVerNb[face],
						edgeqty + 1);

  pos = (ori == 1) ? 0 : 1;
  (*pTess).FaceVerNb[face][edgeqty] = (*pTess).EdgeVerNb[edge][pos];

  if (edgeqty > 1)
    if ((*pTess).FaceVerNb[face][edgeqty] ==
	(*pTess).FaceVerNb[face][edgeqty - 1])
    {
      printf ("trying to add ver %d to face %d, but ver just recorded\n",
	      (*pTess).FaceVerNb[face][edgeqty], face);
      ut_error_reportbug ();
    }

  return;
}

void
neut_tess_cell_addcentre (struct TESS *pTess, int cell, double *centre,
                          double weight)
{
  (*pTess).SeedCoo[cell] = ut_realloc_1d ((*pTess).SeedCoo[cell], 3);
  ut_array_1d_memcpy ((*pTess).SeedCoo[cell], 3, centre);

  (*pTess).SeedWeight = ut_realloc_1d ((*pTess).SeedWeight,
				       (*pTess).CellQty + 1);
  (*pTess).SeedWeight[cell] = weight;

  return;
}

void
neut_tess_poly_addface (struct TESS *pTess, int poly, int face, int ori)
{
  int faceqty;

  if (poly < 0 || face < 0 || (ori != 1 && ori != -1))
  {
    printf ("poly = %d < 0 || face = %d < 0 || ori = %d != 1 and -1\n",
	    poly, face, ori);
    ut_error_reportbug ();
  }

  faceqty = ++(*pTess).PolyFaceQty[poly];
  (*pTess).PolyFaceNb[poly] = ut_realloc_1d_int ((*pTess).PolyFaceNb[poly],
						 faceqty + 1);
  (*pTess).PolyFaceOri[poly] = ut_realloc_1d_int ((*pTess).PolyFaceOri[poly],
						  faceqty + 1);

  (*pTess).PolyFaceNb[poly][faceqty] = face;
  (*pTess).PolyFaceOri[poly][faceqty] = ori;

  return;
}

void
neut_tess_face_addeq (struct TESS *pTess, int face, double *eq)
{
  (*pTess).FaceEq[face] = ut_realloc_1d ((*pTess).FaceEq[face], 4);
  ut_array_1d_memcpy ((*pTess).FaceEq[face], 4, eq);

  return;
}

int
neut_tess_adddomver (struct TESS *pTess, double *coo)
{
  (*pTess).DomVerQty++;
  (*pTess).DomVerCoo
    = ut_realloc_2d_addline ((*pTess).DomVerCoo, (*pTess).DomVerQty + 1, 3);
  ut_array_1d_memcpy ((*pTess).DomVerCoo[(*pTess).DomVerQty], 3, coo);

  (*pTess).DomVerEdgeQty = ut_realloc_1d_int ((*pTess).DomVerEdgeQty,
					   (*pTess).DomVerQty + 1);
  (*pTess).DomVerEdgeQty[(*pTess).DomVerQty] = 0;

  (*pTess).DomVerEdgeNb = ut_realloc_1d_pint ((*pTess).DomVerEdgeNb,
					   (*pTess).DomVerQty + 1);
  (*pTess).DomVerEdgeNb[0] = NULL;
  (*pTess).DomVerEdgeNb[(*pTess).DomVerQty] = NULL;

  (*pTess).DomVerLabel = ut_realloc_1d_pchar ((*pTess).DomVerLabel,
					     (*pTess).DomVerQty + 1);
  (*pTess).DomVerLabel[(*pTess).DomVerQty] = NULL;

  (*pTess).DomTessVerNb = ut_realloc_1d_int ((*pTess).DomTessVerNb,
					     (*pTess).DomVerQty + 1);
  (*pTess).DomTessVerNb[(*pTess).DomVerQty] = 0;

  return (*pTess).DomVerQty;
}

int
neut_tess_adddomedge (struct TESS *pTess, int ver1, int ver2)
{
  (*pTess).DomEdgeQty++;
  (*pTess).DomEdgeVerNb = ut_realloc_2d_int_addline ((*pTess).DomEdgeVerNb,
						     (*pTess).DomEdgeQty + 1, 2);
  (*pTess).DomEdgeVerNb[0] = NULL;

  ut_array_1d_int_set_2 ((*pTess).DomEdgeVerNb[(*pTess).DomEdgeQty], ver1, ver2);

  (*pTess).DomEdgeFaceNb
    = ut_realloc_1d_pint ((*pTess).DomEdgeFaceNb, (*pTess).DomEdgeQty + 1);
  (*pTess).DomEdgeFaceNb[(*pTess).DomEdgeQty] = ut_alloc_1d_int (2);

  (*pTess).DomEdgeLabel = ut_realloc_1d_pchar ((*pTess).DomEdgeLabel,
					     (*pTess).DomEdgeQty + 1);
  (*pTess).DomEdgeLabel[(*pTess).DomEdgeQty] = NULL;

  (*pTess).DomTessEdgeQty = ut_realloc_1d_int ((*pTess).DomTessEdgeQty,
					       (*pTess).DomEdgeQty + 1);
  (*pTess).DomTessEdgeQty[(*pTess).DomEdgeQty] = 0;

  (*pTess).DomTessEdgeNb = ut_realloc_1d_pint ((*pTess).DomTessEdgeNb,
					     (*pTess).DomEdgeQty + 1);
  (*pTess).DomTessEdgeNb[0] = NULL;
  (*pTess).DomTessEdgeNb[(*pTess).DomEdgeQty] = NULL;

  return (*pTess).DomEdgeQty;
}

int
neut_tess_adddomface_alloc (struct TESS *pTess)
{
  (*pTess).DomFaceQty++;

  (*pTess).DomFaceLabel = ut_realloc_1d_pchar ((*pTess).DomFaceLabel,
					     (*pTess).DomFaceQty + 1);
  (*pTess).DomFaceLabel[(*pTess).DomFaceQty] = NULL;

  (*pTess).DomFaceEq = ut_realloc_2d_addline ((*pTess).DomFaceEq,
					      (*pTess).DomFaceQty + 1, 4);
  (*pTess).DomFaceEq[0] = NULL;

  (*pTess).DomFaceVerQty = ut_realloc_1d_int ((*pTess).DomFaceVerQty,
                                              (*pTess).DomFaceQty + 1);
  (*pTess).DomFaceVerQty[(*pTess).DomFaceQty] = 0;

  (*pTess).DomFaceVerNb
    = ut_realloc_1d_pint ((*pTess).DomFaceVerNb, (*pTess).DomFaceQty + 1);
  (*pTess).DomFaceVerNb[(*pTess).DomFaceQty] = NULL;

  (*pTess).DomFaceEdgeNb
    = ut_realloc_1d_pint ((*pTess).DomFaceEdgeNb, (*pTess).DomFaceQty + 1);
  (*pTess).DomFaceEdgeNb[(*pTess).DomFaceQty] = NULL;

  (*pTess).DomTessFaceQty = ut_realloc_1d_int ((*pTess).DomTessFaceQty,
					       (*pTess).DomFaceQty + 1);
  (*pTess).DomTessFaceQty[(*pTess).DomFaceQty] = 0;

  (*pTess).DomTessFaceNb = ut_realloc_1d_pint ((*pTess).DomTessFaceNb,
					     (*pTess).DomFaceQty + 1);
  (*pTess).DomTessFaceNb[0] = NULL;
  (*pTess).DomTessFaceNb[(*pTess).DomFaceQty] = NULL;

  return (*pTess).DomFaceQty;
}

void
neut_tess_init_veredge (struct TESS *pTess)
{
  int i, j, ver;

  (*pTess).VerEdgeQty = ut_alloc_1d_int ((*pTess).VerQty + 1);
  (*pTess).VerEdgeNb = ut_alloc_1d_pint ((*pTess).VerQty + 1);
  for (i = 1; i <= (*pTess).EdgeQty; i++)
    for (j = 0; j < 2; j++)
    {
      ver = (*pTess).EdgeVerNb[i][j];
      (*pTess).VerEdgeQty[ver]++;
      (*pTess).VerEdgeNb[ver]
	= ut_realloc_1d_int ((*pTess).VerEdgeNb[ver],
			     (*pTess).VerEdgeQty[ver]);
      (*pTess).VerEdgeNb[ver][(*pTess).VerEdgeQty[ver] - 1] = i;
    }

  return;
}

void
neut_tess_init_edgeface (struct TESS *pTess)
{
  int i, j, edge;

  (*pTess).EdgeFaceQty = ut_alloc_1d_int ((*pTess).EdgeQty + 1);
  (*pTess).EdgeFaceNb = ut_alloc_1d_pint ((*pTess).EdgeQty + 1);
  for (i = 1; i <= (*pTess).FaceQty; i++)
    for (j = 1; j <= (*pTess).FaceVerQty[i]; j++)
    {
      edge = (*pTess).FaceEdgeNb[i][j];
      (*pTess).EdgeFaceQty[edge]++;
      (*pTess).EdgeFaceNb[edge]
	= ut_realloc_1d_int ((*pTess).EdgeFaceNb[edge],
			     (*pTess).EdgeFaceQty[edge]);
      (*pTess).EdgeFaceNb[edge][(*pTess).EdgeFaceQty[edge] - 1] = i;
    }

  return;
}

void
neut_tess_init_facepoly (struct TESS *pTess)
{
  int i, j, face;
  int *FacePolyQty = NULL;

  FacePolyQty = ut_alloc_1d_int ((*pTess).FaceQty + 1);
  (*pTess).FacePoly = ut_alloc_2d_int ((*pTess).FaceQty + 1, 2);
  for (i = 1; i <= (*pTess).PolyQty; i++)
    for (j = 1; j <= (*pTess).PolyFaceQty[i]; j++)
    {
      face = (*pTess).PolyFaceNb[i][j];
      FacePolyQty[face]++;
      (*pTess).FacePoly[face][FacePolyQty[face] - 1] = i;
    }

  ut_free_1d_int (FacePolyQty);

  return;
}

void
neut_tess_face_fixorifromedges (struct TESS *pTess, int face)
{
  double *n = ut_alloc_1d (3);

  neut_tess_face_normal_fromver (*pTess, face, n);

  if (ut_vector_scalprod ((*pTess).FaceEq[face] + 1, n) < 0)
    ut_array_1d_scale ((*pTess).FaceEq[face], 4, -1);

  ut_free_1d (n);

  return;
}

void
neut_tess_domface_tess (struct TESS Tess, int domface, struct TESS *pT)
{
  int i, j, oldver, oldedge, oldface;
  int verqty, *ver = NULL;
  int edgeqty, *edge = NULL;
  int *oldver_newver = ut_alloc_1d_int (Tess.VerQty + 1);
  int *oldedge_newedge = ut_alloc_1d_int (Tess.EdgeQty + 1);
  int *oldface_newface = ut_alloc_1d_int (Tess.FaceQty + 1);
  int *olddver_newdver = ut_alloc_1d_int (Tess.VerQty + 1);
  int *olddedge_newdedge = ut_alloc_1d_int (Tess.EdgeQty + 1);

  neut_tess_free (pT);
  neut_tess_set_zero (pT);

  (*pT).Dim = 2;
  (*pT).Level = 1;
  (*pT).TessId = 1;
  (*pT).CellQty = Tess.CellQty;

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

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

  (*pT).Type = ut_alloc_1d_char (strlen (Tess.Type) + 1);
  strcpy ((*pT).Type, Tess.Type);

  // Seeds
  (*pT).SeedCoo = ut_alloc_2d ((*pT).CellQty + 1, 3);
  (*pT).SeedWeight = ut_alloc_1d ((*pT).CellQty + 1);

  ut_array_2d_memcpy ((*pT).SeedCoo + 1, (*pT).CellQty, (*pT).Dim,
		      Tess.SeedCoo + 1);
  ut_array_1d_memcpy ((*pT).SeedWeight + 1, (*pT).CellQty, Tess.SeedWeight + 1);

  // Faces
  (*pT).FaceQty = Tess.DomTessFaceQty[domface];
  (*pT).FacePoly = ut_alloc_2d_int ((*pT).FaceQty + 1, 2);
  (*pT).FaceEq = ut_alloc_2d ((*pT).FaceQty + 1, 4);
  (*pT).FaceVerQty = ut_alloc_1d_int ((*pT).FaceQty + 1);
  (*pT).FaceVerNb = ut_alloc_1d_pint ((*pT).FaceQty + 1);
  (*pT).FaceEdgeNb = ut_alloc_1d_pint ((*pT).FaceQty + 1);
  (*pT).FaceEdgeOri = ut_alloc_1d_pint ((*pT).FaceQty + 1);
  (*pT).FaceState = ut_alloc_1d_int ((*pT).FaceQty + 1);
  (*pT).FacePt = ut_alloc_1d_int ((*pT).FaceQty + 1);
  (*pT).FacePtCoo = ut_alloc_2d ((*pT).FaceQty + 1, 3);
  (*pT).FaceDom = ut_alloc_2d_int ((*pT).FaceQty + 1, 2);

  for (i = 1; i <= Tess.DomTessFaceQty[domface]; i++)
  {
    oldface = Tess.DomTessFaceNb[domface][i];
    oldface_newface[oldface] = i;

    ut_array_1d_memcpy ((*pT).FaceEq[i], 4, Tess.FaceEq[oldface]);
    (*pT).FaceVerQty[i] = Tess.FaceVerQty[oldface];
    (*pT).FaceVerNb[i] = ut_alloc_1d_int ((*pT).FaceVerQty[i] + 1);
    ut_array_1d_int_memcpy ((*pT).FaceVerNb[i] + 1, (*pT).FaceVerQty[i],
			    Tess.FaceVerNb[oldface] + 1);
    (*pT).FaceEdgeNb[i] = ut_alloc_1d_int ((*pT).FaceVerQty[i] + 1);
    ut_array_1d_int_memcpy ((*pT).FaceEdgeNb[i] + 1, (*pT).FaceVerQty[i],
			    Tess.FaceEdgeNb[oldface] + 1);
    (*pT).FaceEdgeOri[i] = ut_alloc_1d_int ((*pT).FaceVerQty[i] + 1);
    ut_array_1d_int_memcpy ((*pT).FaceEdgeOri[i] + 1, (*pT).FaceVerQty[i],
			    Tess.FaceEdgeOri[oldface] + 1);
    (*pT).FaceState[i] = Tess.FaceState[oldface];
    (*pT).FacePt[i] = -1; // for a 2D tess, must be -1.
    ut_array_1d_int_memcpy ((*pT).FaceDom[i], 2, Tess.FaceDom[oldface]);
  }

  // Edges
  neut_tess_domface_edges (Tess, domface, &edge, &edgeqty);

  (*pT).EdgeQty = edgeqty;
  (*pT).EdgeVerNb = ut_alloc_2d_int ((*pT).EdgeQty + 1, 2);
  (*pT).EdgeFaceQty = ut_alloc_1d_int ((*pT).EdgeQty + 1);
  (*pT).EdgeFaceNb = ut_alloc_1d_pint ((*pT).EdgeQty + 1);
  (*pT).EdgeLength = ut_alloc_1d ((*pT).EdgeQty + 1);
  (*pT).EdgeState = ut_alloc_1d_int ((*pT).EdgeQty + 1);
  (*pT).EdgeDel = ut_alloc_1d_int ((*pT).EdgeQty + 1);
  (*pT).EdgeDom = ut_alloc_2d_int ((*pT).EdgeQty + 1, 2);

  for (i = 1; i <= edgeqty; i++)
  {
    oldedge = edge[i - 1];
    oldedge_newedge[oldedge] = i;

    ut_array_1d_int_memcpy ((*pT).EdgeVerNb[i], 2, Tess.EdgeVerNb[oldedge]);

    (*pT).EdgeFaceQty[i] = Tess.EdgeFaceQty[oldedge];
    (*pT).EdgeFaceNb[i] = ut_alloc_1d_int ((*pT).EdgeFaceQty[i]);
    ut_array_1d_int_memcpy ((*pT).EdgeFaceNb[i], (*pT).EdgeFaceQty[i],
			    Tess.EdgeFaceNb[oldedge]);

    (*pT).EdgeLength[i] = Tess.EdgeLength[oldedge];
    (*pT).EdgeState[i] = Tess.EdgeState[oldedge];
    (*pT).EdgeDel[i] = Tess.EdgeDel[oldedge];
    ut_array_1d_int_memcpy ((*pT).EdgeDom[i], 2, Tess.EdgeDom[oldedge]);
  }

  // Vertices
  neut_tess_domface_ver (Tess, domface, &ver, &verqty);

  (*pT).VerQty = verqty;
  (*pT).VerCoo = ut_alloc_2d ((*pT).VerQty + 1, 3);
  (*pT).VerEdgeQty = ut_alloc_1d_int ((*pT).VerQty + 1);
  (*pT).VerEdgeNb = ut_alloc_1d_pint ((*pT).VerQty + 1);
  (*pT).VerDom = ut_alloc_2d_int ((*pT).VerQty + 1, 2);
  (*pT).VerState = ut_alloc_1d_int ((*pT).VerQty + 1);

  for (i = 1; i <= verqty; i++)
  {
    oldver = ver[i - 1];
    oldver_newver[oldver] = i;

    ut_array_1d_memcpy ((*pT).VerCoo[i], 3, Tess.VerCoo[oldver]);
    (*pT).VerEdgeQty[i] = Tess.VerEdgeQty[oldver];
    (*pT).VerEdgeNb[i] = ut_alloc_1d_int ((*pT).VerEdgeQty[i]);
    ut_array_1d_int_memcpy ((*pT).VerEdgeNb[i], (*pT).VerEdgeQty[i],
			    Tess.VerEdgeNb[oldver]);
    ut_array_1d_int_memcpy ((*pT).VerDom[i], 2, Tess.VerDom[oldver]);
    (*pT).VerState[i] = Tess.VerState[oldver];
  }

  // Renumbering faces in edges
  for (i = 1; i <= (*pT).EdgeQty; i++)
  {
    for (j = 0; j < (*pT).EdgeFaceQty[i]; j++)
      (*pT).EdgeFaceNb[i][j] = oldface_newface[(*pT).EdgeFaceNb[i][j]];

    (*pT).EdgeFaceQty[i] -=
      ut_array_1d_int_deletencompress ((*pT).EdgeFaceNb[i],
				       (*pT).EdgeFaceQty[i], 0,
				       (*pT).EdgeFaceQty[i]);
  }

  // Renumbering edges in vertices and faces
  for (i = 1; i <= (*pT).VerQty; i++)
  {
    for (j = 0; j < (*pT).VerEdgeQty[i]; j++)
      (*pT).VerEdgeNb[i][j] = oldedge_newedge[(*pT).VerEdgeNb[i][j]];

    (*pT).VerEdgeQty[i] -=
      ut_array_1d_int_deletencompress ((*pT).VerEdgeNb[i],
				       (*pT).VerEdgeQty[i], 0,
				       (*pT).VerEdgeQty[i]);
  }

  for (i = 1; i <= (*pT).FaceQty; i++)
    for (j = 1; j <= (*pT).FaceVerQty[i]; j++)
      (*pT).FaceEdgeNb[i][j] = oldedge_newedge[(*pT).FaceEdgeNb[i][j]];

  // Renumbering vertices in edges and faces
  for (i = 1; i <= (*pT).EdgeQty; i++)
    for (j = 0; j < 2; j++)
      (*pT).EdgeVerNb[i][j] = oldver_newver[(*pT).EdgeVerNb[i][j]];

  for (i = 1; i <= (*pT).FaceQty; i++)
    for (j = 1; j <= (*pT).FaceVerQty[i]; j++)
      (*pT).FaceVerNb[i][j] = oldver_newver[(*pT).FaceVerNb[i][j]];

  // Domain
  (*pT).DomType = ut_alloc_1d_char (strlen (Tess.DomType) + 1);
  strcpy ((*pT).DomType, Tess.DomType);

  // Domain faces
  (*pT).DomFaceQty = 0;

  // Domain edges
  (*pT).DomEdgeQty = Tess.DomFaceVerQty[domface];
  (*pT).DomEdgeLabel = ut_alloc_1d_pchar ((*pT).DomEdgeQty + 1);
  (*pT).DomEdgeVerNb = ut_alloc_2d_int ((*pT).DomEdgeQty + 1, 2);
  (*pT).DomEdgeFaceNb = ut_alloc_2d_int ((*pT).DomEdgeQty + 1, 2);
  (*pT).DomTessEdgeQty = ut_alloc_1d_int ((*pT).DomEdgeQty + 1);
  (*pT).DomTessEdgeNb = ut_alloc_1d_pint ((*pT).DomEdgeQty + 1);

  for (i = 1; i <= Tess.DomFaceVerQty[domface]; i++)
  {
    oldedge = Tess.DomFaceEdgeNb[domface][i];
    olddedge_newdedge[oldedge] = i;

    (*pT).DomEdgeLabel[i]
      = ut_alloc_1d_char (strlen (Tess.DomEdgeLabel[oldedge]) + 1);
    strcpy ((*pT).DomEdgeLabel[i], Tess.DomEdgeLabel[oldedge]);
    ut_string_fnrs ((*pT).DomEdgeLabel[i], Tess.DomFaceLabel[domface], "", 1);

    ut_array_1d_int_memcpy ((*pT).DomEdgeVerNb[i], 2,
			    Tess.DomEdgeVerNb[oldedge]);
    (*pT).DomEdgeFaceNb[i][0] = domface;

    (*pT).DomTessEdgeQty[i] = Tess.DomTessEdgeQty[oldedge];
    (*pT).DomTessEdgeNb[i] = ut_alloc_1d_int ((*pT).DomTessEdgeQty[i] + 1);
    ut_array_1d_int_memcpy ((*pT).DomTessEdgeNb[i] + 1,
			    (*pT).DomTessEdgeQty[i],
			    Tess.DomTessEdgeNb[oldedge] + 1);
  }

  // Domain vertices
  (*pT).DomVerQty = Tess.DomFaceVerQty[domface];
  (*pT).DomVerCoo = ut_alloc_2d ((*pT).DomVerQty + 1, 3);
  (*pT).DomVerLabel = ut_alloc_1d_pchar ((*pT).DomVerQty + 1);
  (*pT).DomVerEdgeQty = ut_alloc_1d_int ((*pT).DomVerQty + 1);
  (*pT).DomVerEdgeNb = ut_alloc_1d_pint ((*pT).DomVerQty + 1);
  (*pT).DomTessVerNb = ut_alloc_1d_int ((*pT).DomVerQty + 1);
  for (i = 1; i <= (*pT).DomVerQty; i++)
  {
    oldver = Tess.DomFaceVerNb[domface][i];
    olddver_newdver[oldver] = i;

    (*pT).DomVerLabel[i]
      = ut_alloc_1d_char (strlen (Tess.DomVerLabel[oldver]) + 1);
    strcpy ((*pT).DomVerLabel[i], Tess.DomVerLabel[oldver]);
    ut_string_fnrs ((*pT).DomVerLabel[i], Tess.DomFaceLabel[domface], "", 1);

    ut_array_1d_memcpy ((*pT).DomVerCoo[i], 3, Tess.DomVerCoo[oldver]);

    (*pT).DomVerEdgeQty[i] = Tess.DomVerEdgeQty[oldver];
    (*pT).DomVerEdgeNb[i] = ut_alloc_1d_int ((*pT).DomVerEdgeQty[i]);
    ut_array_1d_int_memcpy ((*pT).DomVerEdgeNb[i],
			    (*pT).DomVerEdgeQty[i],
			    Tess.DomVerEdgeNb[oldver]);
    (*pT).DomTessVerNb[i] = Tess.DomTessVerNb[oldver];
  }

  // Renumbering domain faces in domain edges
  for (i = 1; i <= (*pT).DomVerQty; i++)
    (*pT).DomEdgeFaceNb[i][0] = 1;

  // Renumbering domain edges in domain vertices
  for (i = 1; i <= (*pT).DomVerQty; i++)
  {
    for (j = 0; j < (*pT).DomVerEdgeQty[i]; j++)
      (*pT).DomVerEdgeNb[i][j] = olddedge_newdedge[(*pT).DomVerEdgeNb[i][j]];

    (*pT).DomVerEdgeQty[i] -=
      ut_array_1d_int_deletencompress ((*pT).DomVerEdgeNb[i],
				       (*pT).DomVerEdgeQty[i], 0,
				       (*pT).DomVerEdgeQty[i]);
  }

  // Renumbering domain vertices in domain edges
  for (i = 1; i <= (*pT).DomEdgeQty; i++)
    for (j = 0; j < 2; j++)
      (*pT).DomEdgeVerNb[i][j] = olddver_newdver[(*pT).DomEdgeVerNb[i][j]];

  // Renumbering edges in domain edges
  for (i = 1; i <= (*pT).DomEdgeQty; i++)
    for (j = 1; j <= (*pT).DomTessEdgeQty[i]; j++)
      (*pT).DomTessEdgeNb[i][j] = oldedge_newedge[(*pT).DomTessEdgeNb[i][j]];

  // Renumbering vers in domain vers
  for (i = 1; i <= (*pT).DomVerQty; i++)
    (*pT).DomTessVerNb[i] = oldver_newver[(*pT).DomTessVerNb[i]];

  // Renumbering domain faces in faces
  for (i = 1; i <= (*pT).FaceQty; i++)
    (*pT).FaceDom[i][1] = 1;

  // Renumbering domain edges and faces in edges
  for (i = 1; i <= (*pT).EdgeQty; i++)
    if ((*pT).EdgeDom[i][0] == 2)
      (*pT).EdgeDom[i][1] = 1;
    else if ((*pT).EdgeDom[i][0] == 1)
    {
      (*pT).EdgeDom[i][1] = olddedge_newdedge[(*pT).EdgeDom[i][1]];
      if ((*pT).EdgeDom[i][1] == 0)
	ut_error_reportbug ();
    }

  // Renumbering domain edges and faces in vertices
  for (i = 1; i <= (*pT).VerQty; i++)
    if ((*pT).VerDom[i][0] == 2)
      (*pT).VerDom[i][1] = 1;
    else if ((*pT).VerDom[i][0] == 1)
      (*pT).VerDom[i][1] = olddedge_newdedge[(*pT).VerDom[i][1]];
    else if ((*pT).VerDom[i][0] == 0)
      (*pT).VerDom[i][1] = olddver_newdver[(*pT).VerDom[i][1]];

  // Scale information
  if (Tess.ScaleQty > 0)
  {
    (*pT).ScaleQty = Tess.ScaleQty;
    (*pT).ScaleCell = ut_alloc_2d_int (Tess.ScaleQty,
				       Tess.CellQty + 1);
    ut_array_2d_int_memcpy ((*pT).ScaleCell + 1, Tess.ScaleQty - 1,
			    Tess.CellQty + 1, Tess.ScaleCell + 1);
  }

  ut_free_1d_int (oldver_newver);
  ut_free_1d_int (oldedge_newedge);
  ut_free_1d_int (oldface_newface);
  ut_free_1d_int (olddver_newdver);
  ut_free_1d_int (olddedge_newdedge);
  ut_free_1d_int (ver);
  ut_free_1d_int (edge);

  return;
}

void
neut_tess_init_domfaceeq (struct TESS *pTess)
{
  int i, j, face, poly, ori;
  double* eq = ut_alloc_1d (4);

  if ((*pTess).DomFaceEq == NULL)
    (*pTess).DomFaceEq = ut_alloc_2d ((*pTess).DomFaceQty + 1, 4);

  for (i = 1; i <= (*pTess).DomFaceQty; i++)
  {
    ut_array_1d_zero ((*pTess).DomFaceEq[i], 4);

    for (j = 1; j <= (*pTess).DomTessFaceQty[i]; j++)
    {
      face = (*pTess).DomTessFaceNb[i][j];

      poly = (*pTess).FacePoly[(*pTess).DomTessFaceNb[i][j]][0];
      neut_tess_poly_face_ori (*pTess, poly, face, &ori);
      if (ori == 0)
	ut_error_reportbug ();
      ut_array_1d_memcpy (eq, 4, (*pTess).FaceEq[face]);
      ut_array_1d_scale (eq, 4, ori);
      ut_array_1d_add ((*pTess).DomFaceEq[i], eq, 4, (*pTess).DomFaceEq[i]);
    }
    ut_array_1d_scale ((*pTess).DomFaceEq[i], 4,
	               1 / ut_array_1d_norm ((*pTess).DomFaceEq[i] + 1, 3));
  }

  ut_free_1d (eq);

  return;
}
