← Back to team overview

yade-dev team mailing list archive

[svn] r1747 - in trunk/extra/SpherePadder: . SpherePackingTriangulation

 

Author: richefeu
Date: 2009-04-06 17:42:25 +0200 (Mon, 06 Apr 2009)
New Revision: 1747

Modified:
   trunk/extra/SpherePadder/CellPartition.cpp
   trunk/extra/SpherePadder/CellPartition.hpp
   trunk/extra/SpherePadder/SpherePackingTriangulation/SpherePackingTriangulation.cpp
   trunk/extra/SpherePadder/SpherePackingTriangulation/SpherePackingTriangulation.hpp
   trunk/extra/SpherePadder/SpherePadder.cpp
   trunk/extra/SpherePadder/SpherePadder.hpp
   trunk/extra/SpherePadder/main.cpp
Log:
- overlap with spheres inserted by user -> bug fixed
- Densification begins to work


Modified: trunk/extra/SpherePadder/CellPartition.cpp
===================================================================
--- trunk/extra/SpherePadder/CellPartition.cpp	2009-04-06 10:26:50 UTC (rev 1746)
+++ trunk/extra/SpherePadder/CellPartition.cpp	2009-04-06 15:42:25 UTC (rev 1747)
@@ -45,7 +45,7 @@
   ksize = (unsigned int)((zmax - zmin) / (security_factor * mesh.mean_segment_length));
   if (ksize < 1) ksize = 1;
   
-  //cerr << "nb cells: " << isize << ", " << jsize << ", " << ksize << endl;
+  cout << "nb cells: " << isize << ", " << jsize << ", " << ksize << endl;
   
   vector<unsigned int> kvec;
   for (unsigned int k = 0 ; k < ksize ; ++k) kvec.push_back(0);
@@ -93,8 +93,12 @@
  
   cell[ cellId[current_i][current_j][current_k] ].sphereId.push_back(n);
 }
-   
 
+void CellPartition::add_in_cell(unsigned int n, unsigned int i, unsigned int j, unsigned int k)
+{
+  cell[ cellId[i][j][k] ].sphereId.push_back(n);
+}
+
 void CellPartition::locateCellOf(double x, double y, double z)
 {
   int i,j,k;

Modified: trunk/extra/SpherePadder/CellPartition.hpp
===================================================================
--- trunk/extra/SpherePadder/CellPartition.hpp	2009-04-06 10:26:50 UTC (rev 1746)
+++ trunk/extra/SpherePadder/CellPartition.hpp	2009-04-06 15:42:25 UTC (rev 1747)
@@ -39,6 +39,7 @@
     CellPartition();
     void init(TetraMesh & mesh, double security_factor = 1.0);
     void add(unsigned int n, double x, double y, double z);
+	void add_in_cell(unsigned int n, unsigned int i, unsigned int j, unsigned int k);
     void locateCellOf(double x, double y, double z);
     
     Cell& get_cell   (unsigned int i,unsigned int j,unsigned int k) { return cell[ cellId[i][j][k] ]; }

Modified: trunk/extra/SpherePadder/SpherePackingTriangulation/SpherePackingTriangulation.cpp
===================================================================
--- trunk/extra/SpherePadder/SpherePackingTriangulation/SpherePackingTriangulation.cpp	2009-04-06 10:26:50 UTC (rev 1746)
+++ trunk/extra/SpherePadder/SpherePackingTriangulation/SpherePackingTriangulation.cpp	2009-04-06 15:42:25 UTC (rev 1747)
@@ -61,15 +61,43 @@
   return true;
 }
   
-
-  
 float SpherePackingTriangulation::current_tetrahedron_get_volume()
 {
   Cell_handle cell = tetrahedron_iterator;
   return (Tetrahedron(cell->vertex(0)->point(), cell->vertex(1)->point(),
           cell->vertex(2)->point(), cell->vertex (3)->point())).volume();
 }
-  
+
+// warning order of radii is the same as id
+void SpherePackingTriangulation::current_tetrahedron_get_circumcenter(Real R1,Real R2,Real R3,Real R4,Real& x, Real& y, Real& z)
+{
+  Cell_handle cell = tetrahedron_iterator;
+
+   Real p1x = cell->vertex(0)->point().x();
+   Real p1y = cell->vertex(0)->point().y();
+   Real p1z = cell->vertex(0)->point().z();
+
+   Real p2x = cell->vertex(1)->point().x();
+   Real p2y = cell->vertex(1)->point().y();
+   Real p2z = cell->vertex(1)->point().z();
+
+   Real p3x = cell->vertex(2)->point().x();
+   Real p3y = cell->vertex(2)->point().y();
+   Real p3z = cell->vertex(2)->point().z();
+
+   Real p4x = cell->vertex(3)->point().x();
+   Real p4y = cell->vertex(3)->point().y();
+   Real p4z = cell->vertex(3)->point().z();
+
+    CGAL::weighted_circumcenterC3 (
+                                   p1x, p1y, p1z, R1*R1,
+                                   p2x, p2y, p2z, R2*R2,
+                                   p3x, p3y, p3z, R3*R3,
+                                   p4x, p4y, p4z, R4*R4,
+                                   x, y, z
+                                  );
+}
+
 void SpherePackingTriangulation::current_tetrahedron_get_nodes(unsigned int & id1, unsigned int & id2, unsigned int & id3, unsigned int & id4)
 {
   Cell_handle cell = tetrahedron_iterator;

Modified: trunk/extra/SpherePadder/SpherePackingTriangulation/SpherePackingTriangulation.hpp
===================================================================
--- trunk/extra/SpherePadder/SpherePackingTriangulation/SpherePackingTriangulation.hpp	2009-04-06 10:26:50 UTC (rev 1746)
+++ trunk/extra/SpherePadder/SpherePackingTriangulation/SpherePackingTriangulation.hpp	2009-04-06 15:42:25 UTC (rev 1747)
@@ -83,6 +83,13 @@
   public:
   
     SpherePackingTriangulation();
+	bool has_no_cells() { return (tri.number_of_finite_cells() == 0); }
+	void clear()
+	{
+	tri.clear();
+	volumeAreComputed = false;
+	id_vh_link.clear();
+	}
  
     bool insert_node(Real x, Real y, Real z, unsigned int id, bool isVirtual = false);
   
@@ -94,7 +101,28 @@
   
     float current_tetrahedron_get_volume();
     void  current_tetrahedron_get_nodes(unsigned int & id1, unsigned int & id2, unsigned int & id3, unsigned int & id4);
-    
+    void  current_tetrahedron_get_circumcenter(Real R1,Real R2,Real R3,Real R4,Real& x, Real& y, Real& z);
+
+// TODO
+/*
+void  current_tetrahedron_get_weighted_circumcenter(R1,R2,R3,R4,&x,&y,&z)
+{
+    const CGAL_Sphere& S0 = cell->vertex(0)->point();
+    const CGAL_Sphere& S1 = cell->vertex(1)->point();
+    const CGAL_Sphere& S2 = cell->vertex(2)->point();
+    const CGAL_Sphere& S3 = cell->vertex(3)->point();
+    Real x,y,z;
+
+    CGAL::weighted_circumcenterC3 (
+                                   S0.point().x(), S0.point().y(), S0.point().z(), S0.weight(),
+                                   S1.point().x(), S1.point().y(), S1.point().z(), S1.weight(),
+                                   S2.point().x(), S2.point().y(), S2.point().z(), S2.weight(),
+                                   S3.point().x(), S3.point().y(), S3.point().z(), S3.weight(),
+                                   x, y, z
+                                  );
+}
+*/
+
 };
 
 

Modified: trunk/extra/SpherePadder/SpherePadder.cpp
===================================================================
--- trunk/extra/SpherePadder/SpherePadder.cpp	2009-04-06 10:26:50 UTC (rev 1746)
+++ trunk/extra/SpherePadder/SpherePadder.cpp	2009-04-06 15:42:25 UTC (rev 1747)
@@ -21,7 +21,7 @@
 {
   double d1 = (*(tetra_porosity *)a).void_volume;
   double d2 = (*(tetra_porosity *)b).void_volume;      
-  return (d1 < d2) ? 1 :-1;
+  return ((d1) < (d2)) ? 1 :-1;
 }
 
 int compareDouble (const void * a, const void * b)
@@ -33,126 +33,106 @@
 {
   vector <unsigned int> lst;
   unsigned int nb = 5;
-  
+
   for (unsigned int i = 0 ; i <= nb ; ++i)
-    for (unsigned int j = i+1 ; j <= nb+1 ; ++j)
-      for (unsigned int k = j+1 ; k <= nb+2 ; ++k)
-        for (unsigned int l = k+1 ; l <= nb+3 ; ++l)
   {
-    lst.clear();
-    lst.push_back(i);
-    lst.push_back(j);
-    lst.push_back(k);
-    lst.push_back(l);
-    combination.push_back(lst);
+	for (unsigned int j = i+1 ; j <= nb+1 ; ++j)
+	{
+	  for (unsigned int k = j+1 ; k <= nb+2 ; ++k)
+	  {
+		for (unsigned int l = k+1 ; l <= nb+3 ; ++l)
+		{
+		  lst.clear();
+		  lst.push_back(i);
+		  lst.push_back(j);
+		  lst.push_back(k);
+		  lst.push_back(l);
+		  combination.push_back(lst);
+		}
+	  }
+	}
   }
-        
-   max_overlap_rate = 1e-4;   
-   n1 = n2 = n3 = n4 = n5 = n_densify = 0;  
-   trace_functions = true;
-   meshIsPlugged = false;   
-   probeIsDefined = false;          
-   ratio = 4.0; rmoy = 0.0;
-   virtual_radius_factor = 5.0;
-   
-/* FIXME
-   pour le moment, l'utilisateur ne peut entre qu'un ratio.
-   Le rayon des sphere depend du maillage (des longueurs des segments)
-*/
-
-}
-
-void SpherePadder::check_inProbe(unsigned int i)
-{
-  if (!probeIsDefined)    return;
-  if (sphere[i].R <= 0.0) return;
   
-  double dx = sphere[i].x - xProbe;
-  double dy = sphere[i].y - yProbe;
-  double dz = sphere[i].z - zProbe;
-  double squared_distance = dx*dx + dy*dy + dz*dz;
-  if (squared_distance + sphere[i].R*sphere[i].R < RProbe * RProbe) sphereInProbe.push_back(i);
+  n1 = n2 = n3 = n4 = n5 = n_densify = 0;
+  trace_functions = true;
+  meshIsPlugged = false;
+  probeIsDefined = false;
+  RadiusDataIsOK = RadiusIsSet = false;
+  
+  max_overlap_rate = 1e-4;
+  virtual_radius_factor = 100.0;
 }
 
-void SpherePadder::add_spherical_probe(double Rfact)
+void SpherePadder::setRadiusRatio(double r)
 {
-  double xmin,xmax;
-  double ymin,ymax;
-  double zmin,zmax;
-  double R;
+  r = fabs(r);
+  if (r < 1.0) ratio = 1.0/r;
+  else ratio = r;
   
-  xmin=xmax=mesh->node[0].x;
-  ymin=ymax=mesh->node[0].y;
-  zmin=zmax=mesh->node[0].z;
-  for (unsigned int i = 1 ; i < mesh->node.size() ; ++i)
+  if (meshIsPlugged)
   {
-    xmin = (xmin > mesh->node[i].x) ? mesh->node[i].x : xmin;
-    xmax = (xmax < mesh->node[i].x) ? mesh->node[i].x : xmax; 
-    ymin = (ymin > mesh->node[i].y) ? mesh->node[i].y : ymin;
-    ymax = (ymax < mesh->node[i].y) ? mesh->node[i].y : ymax;
-    zmin = (zmin > mesh->node[i].z) ? mesh->node[i].z : zmin;
-    zmax = (zmax < mesh->node[i].z) ? mesh->node[i].z : zmax;
+	rmoy = 0.125 * mesh->mean_segment_length; // 1/8 = 0.125
+	rmin = (2.0 * rmoy) / (ratio + 1.0);
+	rmax = 2.0 * rmoy - rmin;
+	dr = rmax - rmoy;
+	RadiusDataIsOK = true;
+	cout << "rmin = " << rmin << endl;
+	cout << "rmax = " << rmax << endl;
   }
-  xProbe = 0.5 * (xmin + xmax);
-  yProbe = 0.5 * (ymin + ymax);
-  zProbe = 0.5 * (zmin + zmax);
-  RProbe = (xmax - xmin);
-  RProbe = (RProbe < (R = ymax - ymin)) ? RProbe : R;
-  RProbe = (RProbe < (R = zmax - zmin)) ? RProbe : R;
-  RProbe *= 0.5 * Rfact;
-  probeIsDefined = true;
-  compacity_file.open("compacity.dat");
+  else
+  {
+  rmin = rmax = rmoy = 0.0;
+  RadiusDataIsOK = false;
+  // rmin, rmax and rmoy will be calculated in plugTetraMesh
+  }
+  RadiusIsSet = true;
 }
-            
-double SpherePadder::compacity_in_probe(unsigned int ninsered)
+
+void SpherePadder::setRadiusRange(double min, double max)
 {
-  if (!probeIsDefined) return -1.0;
-  
-  double dr = 0.0;
-  double Vs = 0.0;
-  double fact = 1.333333333 * M_PI;
-  for (unsigned int i = 1 ; i < sphereInProbe.size() ; ++i)
+  if (min > max)
   {
-    Vs += fact * sphere[i].R * sphere[i].R * sphere[i].R;
+	rmin = max;
+	rmax = min;
   }
-  
-  // TODO ameliorer cette fonction en prennant en compte les spheres coupees...
-  
-  dr = Vs / (fact*RProbe*RProbe*RProbe);
-  compacity_file << ninsered << ' ' << dr << endl;
-  return (dr);
+  else
+  {
+	rmin = min;
+	rmax = max;
+  }
+  ratio = rmax/rmin;
+  rmoy = 0.5*(rmin+rmax);
+  RadiusDataIsOK = true;
+  RadiusIsSet = true;
 }
 
+
 void SpherePadder::plugTetraMesh (TetraMesh * pluggedMesh)
 {
   mesh = pluggedMesh;
   partition.init(*mesh);
   meshIsPlugged = true;
-	
-  // TODO mettre ce qui suite dans une fonction 'init()'
-  // Si l'utilisateur n'a choisi qu'une valeur de ratio, 
-  // on cree les valeur de rmin et rmax:
-  if (rmoy == 0 && ratio > 0)
-  {
-	rmoy = 0.125 * mesh->mean_segment_length; // 1/8 = 0.125
-	rmin = (2.0 * rmoy) / (ratio + 1.0); 
-	rmax = 2.0 * rmoy - rmin; 
-	dr = rmax - rmoy;
-        cerr << "rmax = " << rmax << endl;
-  }
+
+  cout << "mesh->mean_segment_length = " << mesh->mean_segment_length << endl;
+  cout << "mesh->min_segment_length  = " << mesh->min_segment_length << endl;
+  cout << "mesh->max_segment_length  = " << mesh->max_segment_length << endl;
+  
+  if (!RadiusDataIsOK && RadiusIsSet && ratio != 0.0) setRadiusRatio(ratio);
+  else cerr << "@SpherePadder::plugTetraMesh, no radius range defined!" << endl;
+  
 }
 
 void SpherePadder::pad_5 ()
 {
   if (mesh == 0) 
   {
-    cerr << "SpherePadder::pad_5, no mesh defined!" << endl;
+    cerr << "@SpherePadder::pad_5, no mesh defined!" << endl;
     return;
   }
     
   if (!(mesh->isOrganized)) 
   {
-    cerr << "SpherePadder::pad_5, mesh is not valid!" << endl;
+    cerr << "@SpherePadder::pad_5, mesh is not valid!" << endl;
     return;
   }
   
@@ -187,86 +167,229 @@
   
 }
 
-void SpherePadder::densify()   // TODO FIXME loop until target solid fraction is reached
+void SpherePadder::densify()
 {
   BEGIN_FUNCTION ("Densify");
+  unsigned int added = 0, back_added = 0;
+  unsigned int nbfail = 0;
+  unsigned int max_iter_densify = 40;
+  unsigned int i;
+  
+  repack_null_radii();
+  
+  for (i = 0 ; i < max_iter_densify ; ++i)
+  {
 
+	// CRITERE BIDON !!!!! WARNING
+  if ((added = iter_densify()) == back_added)
+  {
+	if (++nbfail == 3) { cout << "@densify, cannot add more spheres with this ratio" << endl; break; }
+  }
+  else nbfail = 0;
+  
+  cout << "iter " << i << ", nb spheres = " << sphere.size() /*- nzero*/ << ", added = " << added << endl;
+  back_added = added;
+  }
+  
+  if (i == max_iter_densify) cout << "@densify, maximum number of iteration reached" << endl;
+  
+  END_FUNCTION;
+}
+
+void SpherePadder::repack_null_radii() // TODO FIXME loop until target solid fraction is reached
+{  
+  for (unsigned int i = 0 ; i < sphere.size() ; i++)
+  {
+	if (sphere[i].R > 0.0) continue;
+    place_sphere_4contacts(i);
+  }
+}
+
+unsigned int SpherePadder::iter_densify(unsigned int nb_check)   
+{
+  unsigned int nb_added = 0, total_added = 0;
   tetra_porosity P;
-  Sphere S,S1,S2,S3,S4;
-  bool can_be_added;
-  S.type = INSERTED_BY_USER;//FROM_TRIANGULATION;
-  unsigned int ns = sphere.size(); 
+  Sphere S;
+  S.type = FROM_TRIANGULATION;
+  unsigned int ns = sphere.size();
+  unsigned int failure;
+  unsigned int nbVirtual;
+  //double Volume_min = 1.333333333*M_PI*rmin*rmin*rmin;
   
-  //place_virtual_spheres();
+  // TODO add bool VirtualSpheresOK
 
-  // TODO clear triangulation
+  triangulation.clear();
   for (unsigned int i = 0 ; i < sphere.size() ; i++)
   {
 	if (sphere[i].R <= 0.0) continue;
-	triangulation.insert_node(sphere[i].x, sphere[i].y, sphere[i].z, i, false);
+	triangulation.insert_node(sphere[i].x, sphere[i].y, sphere[i].z, i, (sphere[i].type == VIRTUAL));
   }
-
-  if (!tetra_porosities.empty()) tetra_porosities.clear();
-  // FIXME if triangulation is empty ...
+  if (triangulation.has_no_cells()) return total_added;
+  
+  tetra_porosities.clear();
   triangulation.init_current_tetrahedron();
   do
   {
 	triangulation.current_tetrahedron_get_nodes(P.id1,P.id2,P.id3,P.id4);
-	if (P.id1>=ns || P.id2>=ns || P.id3>=ns || P.id4>=ns) continue;
+	if (P.id1 >= ns || P.id2 >= ns || P.id3 >= ns || P.id4 >= ns) continue; // FIXME why ?
+	  
+	nbVirtual = 0;
+	if (sphere[P.id1].type == VIRTUAL) ++nbVirtual; 
+	if (sphere[P.id2].type == VIRTUAL) ++nbVirtual;
+	if (sphere[P.id3].type == VIRTUAL) ++nbVirtual;
+	if (sphere[P.id4].type == VIRTUAL) ++nbVirtual;
+	if (nbVirtual == 4) continue;
+
+/*
+	if (squared_distance_centre_spheres(P.id1, P.id2) > 0.01) continue;
+	if (squared_distance_centre_spheres(P.id1, P.id3) > 0.01) continue;
+	if (squared_distance_centre_spheres(P.id1, P.id4) > 0.01) continue;
+	if (squared_distance_centre_spheres(P.id2, P.id3) > 0.01) continue;
+	if (squared_distance_centre_spheres(P.id2, P.id4) > 0.01) continue;
+	if (squared_distance_centre_spheres(P.id3, P.id4) > 0.01) continue;
+*/
+
 	P.volume = triangulation.current_tetrahedron_get_volume();
 	P.void_volume = P.volume - solid_volume_of_tetrahedron(sphere[P.id1], sphere[P.id2], sphere[P.id3], sphere[P.id4]);
-	if (P.void_volume>0.0)
+	if (P.void_volume > /*Volume_min*/ 0.0 || nbVirtual > 0)
 	{
 	  tetra_porosities.push_back(P);
 	}
   } while (triangulation.next_tetrahedron());
   
-  // sort tetrahdrons from big to small void volumes 
+  // sort tetrahdrons from bigger to smaller void volumes 
   qsort(&(tetra_porosities[0]),tetra_porosities.size(),sizeof(tetra_porosity),compare_tetra_porosity);
 
-
-  // TODO FIXME exclude tetra that involve virtual spheres
   for (unsigned int i = 0 ; i < tetra_porosities.size() ; i++)
-  {
-	//cout << tetra_porosities[i].volume  << "\t" << tetra_porosities[i].void_volume << endl;
-	//if (tetra_porosities[i].void_volume > 0.0)
+  {	
+	failure = place_fifth_sphere(tetra_porosities[i].id1,tetra_porosities[i].id2,tetra_porosities[i].id3,tetra_porosities[i].id4,S);
 
-	S1 = sphere[tetra_porosities[i].id1];
-	S2 = sphere[tetra_porosities[i].id2];
-	S3 = sphere[tetra_porosities[i].id3];
-	S4 = sphere[tetra_porosities[i].id4];
+	if (!failure)
+	{
+	  failure = check_overlaps(S,ns+1); // ns+1 i.e. on exclut aucune sphere
+	}
+	else // failure 
+	{
+// 	  Sphere & S1 = sphere[tetra_porosities[i].id1];
+// 	  Sphere & S2 = sphere[tetra_porosities[i].id2];
+// 	  Sphere & S3 = sphere[tetra_porosities[i].id3];
+// 	  Sphere & S4 = sphere[tetra_porosities[i].id4];
 
-	can_be_added  = (S1.type != VIRTUAL);
-	can_be_added &= (S2.type != VIRTUAL);
-	can_be_added &= (S3.type != VIRTUAL);
-	can_be_added &= (S4.type != VIRTUAL);
+	  /*
+	  CGAL::weighted_circumcenterC3 (
+	                                 S1.x, S1.y, S1.z, S1.R * S1.R,
+									 S2.x, S2.y, S2.z, S2.R * S2.R,
+									 S3.x, S3.y, S3.z, S3.R * S3.R,
+									 S4.x, S4.y, S4.z, S4.R * S4.R,
+									 S.x, S.y, S.z
+									 );
+	  */
+
+      
+
+// 	  double distance_min = distance_centre_spheres(S,S1) - S1.R;
+// 	  double distance;
+// 	  distance_min = (distance_min < (distance = distance_centre_spheres(S,S2) - S2.R)) ? distance_min : distance;
+// 	  distance_min = (distance_min < (distance = distance_centre_spheres(S,S3) - S3.R)) ? distance_min : distance;
+// 	  distance_min = (distance_min < (distance = distance_centre_spheres(S,S4) - S4.R)) ? distance_min : distance;
+// 	  S.R = distance_min;
+// 	  if (S.R > rmax) S.R = rmax;
+	  // TODO mettre en contact
+
+      S.R = rmin; // test
+
+      //if (S.R >= rmin)
+	  {
+//failure = 0;
+		failure = check_overlaps(S,ns+10);
+	  }
+	}
 	
-    if (can_be_added)	
+	if(!failure)
 	{
-// TODO write a function 'try_to_place_into(id1,id2,id3,id4)'
+	  vector<neighbor_with_distance> neighbor;
+	  build_sorted_list_of_neighbors(S, neighbor);
 	  
-	  if( place_fifth_sphere(tetra_porosities[i].id1,tetra_porosities[i].id2,tetra_porosities[i].id3,tetra_porosities[i].id4,S) )
+	  S.R += neighbor[0].distance;
+      
+	  if (S.R >= rmin && S.R <= rmax)
 	  {
-		sphere.push_back(S);
+		sphere.push_back(S);++(n_densify);
+		partition.add(ns,S.x,S.y,S.z);
+		triangulation.insert_node(S.x,S.y,S.z,ns,false); // necessary to compute mean solid fraction
+		++ns; ++nb_added; ++total_added;
 	  }
+	}
 
-	  /*
-	  S.x = 0.25 * (S1.x + S2.x + S3.x + S4.x);
-	  S.y = 0.25 * (S1.y + S2.y + S3.y + S4.y);
-	  S.z = 0.25 * (S1.z + S2.z + S3.z + S4.z);
-	  S.R = rmin;
-
-	  sphere.push_back(S); 
-	  place_sphere_4contacts(ns,4);
-	  ++ns;
-	  */
+	// check if we must stop
+	if (nb_added >= nb_check)
+	{
+	  //cout << "check, total_added = " << total_added << endl;
+	  nb_added = 0;
+	  // getMeanSolidFraction();
 	}
   }
 
-  END_FUNCTION;
+return total_added;
 }
 
+void SpherePadder::save_tri_mgpost (const char* name)
+{
+  // triangulation
+  triangulation.clear();
+  for (unsigned int i = 0 ; i < sphere.size() ; i++)
+  {
+	if (sphere[i].R <= 0.0) continue;
+	triangulation.insert_node(sphere[i].x, sphere[i].y, sphere[i].z, i, (sphere[i].type == VIRTUAL));
+  }
+  if (triangulation.has_no_cells()) return;
 
+  ofstream fmgpost(name);
+  fmgpost << "<?xml version=\"1.0\"?>" << endl
+  << " <mgpost mode=\"3D\">" << endl
+  << "  <state id=\"" << 1 << "\" time=\"" << 0.0 << "\">" << endl;
+
+  double xp,yp,zp,rad,void_volume;
+  unsigned int id1,id2,id3,id4,i=0;
+  tetra_porosities.clear();
+  triangulation.init_current_tetrahedron();
+  do
+  {
+	triangulation.current_tetrahedron_get_nodes(id1,id2,id3,id4);
+	//if(sphere[id1].type == VIRTUAL && sphere[id2].type == VIRTUAL && sphere[id3].type == VIRTUAL && sphere[id4].type == VIRTUAL) continue;
+	
+	xp = 0.25*(sphere[id1].x+sphere[id2].x+sphere[id3].x+sphere[id4].x);
+	yp = 0.25*(sphere[id1].y+sphere[id2].y+sphere[id3].y+sphere[id4].y);
+	zp = 0.25*(sphere[id1].z+sphere[id2].z+sphere[id3].z+sphere[id4].z);
+	rad = (sphere[id1].R>sphere[id2].R)?sphere[id1].R:sphere[id2].R;
+	rad = (rad>sphere[id3].R)?rad:sphere[id3].R;
+	rad = (rad>sphere[id4].R)?rad:sphere[id4].R;
+
+	void_volume = triangulation.current_tetrahedron_get_volume() - solid_volume_of_tetrahedron(sphere[id1], sphere[id2], sphere[id3], sphere[id4]);
+	if (void_volume<0.0) void_volume = 0.0;
+	
+	fmgpost << "   <body>" << endl;
+	fmgpost << "    <POLYE id=\"" << ++i << "\" r=\"" << rad << "\">" << endl
+	<< "     <position x=\"" << xp << "\" y=\"" << yp << "\" z=\"" << zp << "\"/>" << endl
+	//<< "     <velocity rot=\"" << void_volume << "\"/>" << endl
+	<< "     <velocity rot=\"" << triangulation.current_tetrahedron_get_volume() << "\"/>" << endl
+	<< "     <node x=\""<< sphere[id1].x-xp << "\" y=\"" << sphere[id1].y-yp << "\" z=\"" << sphere[id1].z-zp << "\"/>" << endl
+	<< "     <node x=\""<< sphere[id2].x-xp << "\" y=\"" << sphere[id2].y-yp << "\" z=\"" << sphere[id2].z-zp << "\"/>" << endl
+	<< "     <node x=\""<< sphere[id3].x-xp << "\" y=\"" << sphere[id3].y-yp << "\" z=\"" << sphere[id3].z-zp << "\"/>" << endl
+	<< "     <node x=\""<< sphere[id4].x-xp << "\" y=\"" << sphere[id4].y-yp << "\" z=\"" << sphere[id4].z-zp << "\"/>" << endl
+	<< "     <face n1=\"0\" n2=\"1\" n3=\"2\"/>" << endl
+	<< "     <face n1=\"0\" n2=\"2\" n3=\"3\"/>" << endl
+	<< "     <face n1=\"0\" n2=\"3\" n3=\"1\"/>" << endl
+	<< "     <face n1=\"1\" n2=\"3\" n3=\"2\"/>" << endl
+	<< "    </POLYE>" << endl << flush;
+	fmgpost << "   </body>" << endl;
+  } while (triangulation.next_tetrahedron());
+  
+  fmgpost << "  </state>" << endl
+  << " </mgpost>" << endl;
+
+}
+
 void SpherePadder::save_mgpost (const char* name)
 {
   BEGIN_FUNCTION ("Save mgp");
@@ -279,19 +402,22 @@
   
   fmgpost << "<?xml version=\"1.0\"?>" << endl
       << " <mgpost mode=\"3D\">" << endl
+	  // Note that number of newcolors is limited in mgpost
       << "  <newcolor name=\"at nodes\"/>" << endl
       << "  <newcolor name=\"at segments\"/>" << endl   
       << "  <newcolor name=\"at faces\"/>" << endl
       << "  <newcolor name=\"at tetra centers\"/>" << endl
       << "  <newcolor name=\"at tetra vertexes\"/>" << endl
 	  << "  <newcolor name=\"insered by user\"/>" << endl
-	  //<< "  <newcolor name=\"from triangulation\"/>" << endl
+	  << "  <newcolor name=\"from triangulation\"/>" << endl
       << "  <state id=\"" << 1 
       << "\" time=\"" << 0.0 << "\">" << endl;
 
   for (unsigned int i = 0 ; i < sphere.size() ; ++i)
   {
-    if (sphere[i].R <= 0.0 && sphere[i].type != AT_NODE) continue;
+	// the sphere with R=0 that are placed at nodes are saved because mgpost needs them
+	// for the display of tetrahdrons.
+    if (sphere[i].R <= 0.0 && sphere[i].type != AT_NODE) continue; 
 	if (sphere[i].type == VIRTUAL) continue;
 
 	
@@ -424,7 +550,6 @@
     if (S.R > rmax) S.R = rmoy + dr * (double)rand()/(double)RAND_MAX;
     
     sphere.push_back(S); ++(n2); 
-    //check_inProbe(ns);compacity_in_probe(ns);
     partition.add(ns,S.x,S.y,S.z);
                 
     mesh->segment[s].sphereId = ns;
@@ -471,16 +596,9 @@
     
     sphere.push_back(S); ++(n3);
     place_sphere_4contacts(ns);
-    //partition.add(ns,S.x,S.y,S.z); // test
     ++ns;
   }
         
-//   for (unsigned int n = (n1+n2) ; n < sphere.size() ; ++n)
-//   {
-//     place_sphere_4contacts(n);
-//     check_inProbe(n);compacity_in_probe(n);
-//   }
-        
   END_FUNCTION;  
 }
 
@@ -510,19 +628,11 @@
 
     S.R = rmin;
                 
-    //S.tetraOwner = t;
-    //mesh->tetraedre[t].sphereId.push_back(ns++);
     sphere.push_back(S); ++(n4);
     place_sphere_4contacts(ns);
     ++ns;
   }
         
-//   for (unsigned int n = (n1+n2+n3) ; n < sphere.size() ; ++n)
-//   {
-//     place_sphere_4contacts(n);
-//     check_inProbe(n);compacity_in_probe(n);
-//   }
-        
   END_FUNCTION;  
 }
 
@@ -552,33 +662,32 @@
 
     S.R = rmin;
                 
-    double pondere = 0.333333333; // FIXME parametrable
+    double pondere = 0.333333333; // FIXME parametrable ?
     for (unsigned int n = 0 ; n < 4 ; ++n)
     {
       S.x = pondere * mesh->node[ T.nodeId[n] ].x + (1.0 - pondere) * centre[0];
       S.y = pondere * mesh->node[ T.nodeId[n] ].y + (1.0 - pondere) * centre[1];
       S.z = pondere * mesh->node[ T.nodeId[n] ].z + (1.0 - pondere) * centre[2];
       
-      //S.tetraOwner = t;
-      //mesh->tetraedre[t].sphereId.push_back(ns++);
       sphere.push_back(S); ++(n5);
 	  place_sphere_4contacts(ns);
 	  ++ns;
     }
   }
         
-//   for (unsigned int n = (n1+n2+n3+n4) ; n < sphere.size() ; ++n)
-//   {
-//     place_sphere_4contacts(n);
-//     check_inProbe(n);compacity_in_probe(n);
-//   }
-//    
   END_FUNCTION; 
 }
-    
 
+double SpherePadder::squared_distance_centre_spheres(unsigned int i, unsigned int j)
+{
+  double lx,ly,lz;
+  lx  = sphere[j].x - sphere[i].x;
+  ly  = sphere[j].y - sphere[i].y;
+  lz  = sphere[j].z - sphere[i].z;
+  return ((lx*lx + ly*ly + lz*lz));
+}
 
-
+// deprecated
 double SpherePadder::distance_spheres(unsigned int i, unsigned int j)
 {
   double lx,ly,lz;
@@ -588,6 +697,15 @@
   return (sqrt(lx*lx + ly*ly + lz*lz) - sphere[i].R - sphere[j].R);
 }
 
+double SpherePadder::distance_spheres(Sphere & S1, Sphere & S2)
+{
+  double lx,ly,lz;
+  lx  = S2.x - S1.x;
+  ly  = S2.y - S1.y;
+  lz  = S2.z - S1.z;
+  return (sqrt(lx*lx + ly*ly + lz*lz) - S1.R - S2.R);
+}
+
 double SpherePadder::distance_centre_spheres(Sphere& S1, Sphere& S2)
 {
   double lx,ly,lz;
@@ -597,44 +715,86 @@
   return (sqrt(lx*lx + ly*ly + lz*lz));
 }
 
-unsigned int SpherePadder::place_sphere_4contacts (unsigned int sphereId, unsigned int nb_combi_max)
-{ 
-  Sphere S = sphere[sphereId];
-  Sphere Sbackup;
-
-  vector<neighbor_with_distance> neighbor;
+void SpherePadder::build_sorted_list_of_neighbors(Sphere & S, vector<neighbor_with_distance> & neighbor)
+{
   neighbor_with_distance N;
-                
+  
   unsigned int id;
   Cell current_cell;
   
   partition.locateCellOf(S.x,S.y,S.z);
+  
+  // Build the local list of neighbors
+  for (unsigned int i = partition.i_down() ; i <= partition.i_up() ; ++i)
+  {
+	for (unsigned int j = partition.j_down() ; j <= partition.j_up() ; ++j)
+	{
+	  for (unsigned int k = partition.k_down() ; k <= partition.k_up() ; ++k)
+	  {
+		
+		current_cell = partition.get_cell(i,j,k);
+		for (unsigned int s = 0 ; s < current_cell.sphereId.size() ; ++s)
+		{
+		  id = current_cell.sphereId[s];
+		  //if (id != sphereId)
+		  {
+			N.sphereId = id;
+			N.distance = distance_spheres(S,sphere[id]);
+			neighbor.push_back(N);
+		  }
+		}
+		
+	  }
+	}
+  }
+  
+  qsort(&(neighbor[0]),neighbor.size(),sizeof(neighbor_with_distance),compare_neighbor_with_distance);
+}
 
-  // Build the list of neighbors
+void SpherePadder::build_sorted_list_of_neighbors(unsigned int sphereId, vector<neighbor_with_distance> & neighbor)
+{
+  neighbor_with_distance N;
+  
+  unsigned int id;
+  Cell current_cell;
+  
+  partition.locateCellOf(sphere[sphereId].x,sphere[sphereId].y,sphere[sphereId].z);
+  
+  // Build the local list of neighbors
   for (unsigned int i = partition.i_down() ; i <= partition.i_up() ; ++i)
   {
-    for (unsigned int j = partition.j_down() ; j <= partition.j_up() ; ++j)
-    {
-      for (unsigned int k = partition.k_down() ; k <= partition.k_up() ; ++k)
-      {
-        
-        current_cell = partition.get_cell(i,j,k);
-        for (unsigned int s = 0 ; s < current_cell.sphereId.size() ; ++s)
-        {
-          id = current_cell.sphereId[s];
-          if (id != sphereId)
-          {
-            N.sphereId = id;
-            N.distance = distance_spheres(sphereId,id);
-            neighbor.push_back(N);
-          }
-        }
-        
-      }
-    }
+	for (unsigned int j = partition.j_down() ; j <= partition.j_up() ; ++j)
+	{
+	  for (unsigned int k = partition.k_down() ; k <= partition.k_up() ; ++k)
+	  {
+		
+		current_cell = partition.get_cell(i,j,k);
+		for (unsigned int s = 0 ; s < current_cell.sphereId.size() ; ++s)
+		{
+		  id = current_cell.sphereId[s];
+		  if (id != sphereId)
+		  {
+			N.sphereId = id;
+			N.distance = distance_spheres(sphereId,id);
+			neighbor.push_back(N);
+		  }
+		}
+		
+	  }
+	}
   }
-      
-  qsort(&(neighbor[0]),neighbor.size(),sizeof(neighbor_with_distance),compare_neighbor_with_distance); 
+  
+  qsort(&(neighbor[0]),neighbor.size(),sizeof(neighbor_with_distance),compare_neighbor_with_distance);
+}
+
+unsigned int SpherePadder::place_sphere_4contacts (unsigned int sphereId, unsigned int nb_combi_max)
+{ 
+  Sphere S = sphere[sphereId];
+  Sphere Sbackup;
+
+  vector<neighbor_with_distance> neighbor;
+  build_sorted_list_of_neighbors(sphereId, neighbor);
+  
   S.R += neighbor[0].distance;
   if (S.R >= rmin && S.R <= rmax) sphere[sphereId].R = S.R;
   else if (S.R > rmax)            sphere[sphereId].R = rmax;
@@ -664,32 +824,10 @@
     
     S = Sbackup;
     failure = place_fifth_sphere(s1,s2,s3,s4,S);
-    
+
     if (!failure)
-	{ 
-      partition.locateCellOf(S.x,S.y,S.z);
-	  unsigned int nb = 0;
-	  for (unsigned int i = partition.i_down() ; i <= partition.i_up() ; ++i)
-	  {
-		for (unsigned int j = partition.j_down() ; j <= partition.j_up() ; ++j)
-		{
-		  for (unsigned int k = partition.k_down() ; k <= partition.k_up() ; ++k)
-		  {
-			current_cell = partition.get_cell(i,j,k);
-			nb += current_cell.sphereId.size(); // FIXME why ??
-			for (unsigned int s = 0 ; s < current_cell.sphereId.size() ; ++s)
-			{
-			  id = current_cell.sphereId[s];
-			  if (id != sphereId && sphere[id].R > 0.0)
-			  {
-				if ((distance_centre_spheres(S,sphere[id]) - (S.R + sphere[id].R)) < -max_overlap_rate * rmin) { failure = 128; break; }
-			  }
-			}
-		  }
-		}
-	  }
-	
-    }  
+	  failure = check_overlaps(S, sphereId);
+	else continue;
 
     if (!failure)
     {
@@ -707,6 +845,33 @@
   return 0;
 }
 
+unsigned int SpherePadder::check_overlaps(Sphere & S, unsigned int excludedId)
+{
+  unsigned int id;
+  Cell current_cell;
+  
+  partition.locateCellOf(S.x,S.y,S.z);
+  for (unsigned int i = partition.i_down() ; i <= partition.i_up() ; ++i)
+  {
+	for (unsigned int j = partition.j_down() ; j <= partition.j_up() ; ++j)
+	{
+	  for (unsigned int k = partition.k_down() ; k <= partition.k_up() ; ++k)
+	  {
+		current_cell = partition.get_cell(i,j,k);
+		for (unsigned int s = 0 ; s < current_cell.sphereId.size() ; ++s)
+		{
+		  id = current_cell.sphereId[s];
+		  if (id != excludedId && sphere[id].R > 0.0)
+		  {
+			if (distance_spheres(S,sphere[id]) < (-max_overlap_rate * rmin)) { return 128; }
+		  }
+		}
+	  }
+	}
+  }
+  return 0;
+}
+
 double SpherePadder::distance_vector3 (double V1[],double V2[])
 {
   double D[3];
@@ -723,15 +888,18 @@
   C1[0] = sphere[s1].x ; C1[1] = sphere[s1].y ; C1[2] = sphere[s1].z ; R1 = sphere[s1].R;  
   C2[0] = sphere[s2].x ; C2[1] = sphere[s2].y ; C2[2] = sphere[s2].z ; R2 = sphere[s2].R; 
   C3[0] = sphere[s3].x ; C3[1] = sphere[s3].y ; C3[2] = sphere[s3].z ; R3 = sphere[s3].R; 
-  C4[0] = sphere[s4].x ; C4[1] = sphere[s4].y ; C4[2] = sphere[s4].z ; R4 = sphere[s4].R; 
+  C4[0] = sphere[s4].x ; C4[1] = sphere[s4].y ; C4[2] = sphere[s4].z ; R4 = sphere[s4].R;
+
+  // rougth estimate of the position
+  // TODO 
   
-  unsigned int fail_det          =  1;
-  unsigned int fail_delta        =  2;
-  unsigned int fail_radius       =  4;
-  unsigned int fail_overlap      =  8;
-  unsigned int fail_gap          = 16;
-  unsigned int fail_radius_range = 32;
-  unsigned int fail_NaN          = 64;
+  unsigned int fail_det          = 0x01;
+  unsigned int fail_delta        = 0x02;
+  unsigned int fail_radius       = 0x04;
+  unsigned int fail_overlap      = 0x08;
+  unsigned int fail_gap          = 0x10;
+  unsigned int fail_radius_range = 0x20;
+  unsigned int fail_NaN          = 0x40;
 
   // (x-x1)^2 + (y-y1)^2 + (z-z1)^2 = (r+r1)^2   (1)
   // (x-x2)^2 + (y-y2)^2 + (z-z2)^2 = (r+r2)^2   (2)
@@ -760,9 +928,9 @@
   double eee = (C1[0]*C1[0] + C1[1]*C1[1] + C1[2]*C1[2] - R1*R1) - (C4[0]*C4[0] + C4[1]*C4[1] + C4[2]*C4[2] - R4*R4);
 
   // compute the determinant of matrix A (system AX = B)
-  //      [a  ,  b,  c];    [x]     [e  -  d*r]
-  //  A = [aa ,bb ,cc ];  X=[y]   B=[ee - dd*r]
-  //      [aaa,bbb,ccc];    [z]     [eee-ddd*r]
+  //      [a  ,  b,  c];    [x]        [e  -  d*r]
+  //  A = [aa ,bb ,cc ];  X=[y]   B(r)=[ee - dd*r]
+  //      [aaa,bbb,ccc];    [z]        [eee-ddd*r]
 
   double DET = a*(bb*ccc-bbb*cc) - aa*(b*ccc-bbb*c) + aaa*(b*cc-bb*c);
   double R = 0.0;
@@ -784,6 +952,7 @@
     double a32 = -(a*bbb-aaa*b)   * inv_DET;
     double a33 =  (a*bb-aa*b)     * inv_DET;
 
+	// A^-1 B(r)
     double xa = -(a11*d + a12*dd + a13*ddd);
     double xb =  (a11*e + a12*ee + a13*eee);
 
@@ -792,7 +961,7 @@
 
     double za = -(a31*d + a32*dd + a33*ddd);
     double zb =  (a31*e + a32*ee + a33*eee);
-
+	
     // Replace x, y and z in Equation (1) and solve the second order equation A*r^2 + B*r + C = 0
 
     double A = xa*xa + ya*ya + za*za - 1.0;
@@ -802,9 +971,9 @@
     double DELTA = B*B - 4.0*A*C;
     double RR1,RR2;
 
-    if (DELTA >= 0.0)
+    if (DELTA >= 0.0) // && A != 0.0
     {
-      double inv_2A = 1.0 / (2.0*A);
+      double inv_2A = 0.5/A;
       double sqrt_DELTA = sqrt(DELTA);
       RR1 = (-B + sqrt_DELTA) * inv_2A;
       RR2 = (-B - sqrt_DELTA) * inv_2A;
@@ -822,6 +991,11 @@
     centre[2] = za * R + zb;
   }
   else return fail_det;
+
+  S.x = centre[0];
+  S.y = centre[1];
+  S.z = centre[2];
+  S.R = R;
   
   // FIXME do not use sqrt to speed up... (squared_distance_vector3)
   // for the moment it is not critical
@@ -832,40 +1006,42 @@
   double distance3 = distance_vector3 (centre,C3) - (R + R3);
   double distance4 = distance_vector3 (centre,C4) - (R + R4);
   
-  double half_distance_rate = -0.5 * max_overlap_rate;
-  if (     ( distance1 < half_distance_rate * (R + R1)) 
-        || ( distance2 < half_distance_rate * (R + R2))
-        || ( distance3 < half_distance_rate * (R + R3)) 
-        || ( distance4 < half_distance_rate * (R + R4)) )
+//   double half_distance_rate = -0.5 * max_overlap_rate;
+//   if (     ( distance1 < half_distance_rate * (R + R1)) 
+//         || ( distance2 < half_distance_rate * (R + R2))
+//         || ( distance3 < half_distance_rate * (R + R3)) 
+//         || ( distance4 < half_distance_rate * (R + R4)) )
+//   { return fail_overlap; }
+
+  double max_overlap = -max_overlap_rate * rmin;
+  if ( ( distance1 < max_overlap)
+	|| ( distance2 < max_overlap)
+	|| ( distance3 < max_overlap)
+	|| ( distance4 < max_overlap) )
   { return fail_overlap; }
   
   // The gap between spheres must not be too large
   double distance_max = max_overlap_rate * rmin;
-  if (     ( distance1 > distance_max) 
-        || ( distance2 > distance_max)
-        || ( distance3 > distance_max) 
-        || ( distance4 > distance_max) )
-  { return fail_gap; } 
+  if ( ( distance1 > distance_max)
+    || ( distance2 > distance_max)
+    || ( distance3 > distance_max)
+    || ( distance4 > distance_max) )
+  { return fail_gap; }
   
-  
   // Check if there is NaN 
-  if (     (centre[0] != centre[0])
-        || (centre[1] != centre[1])
-        || (centre[2] != centre[2])
-        || (R != R))
+  if ( (centre[0] != centre[0])
+    || (centre[1] != centre[1])
+    || (centre[2] != centre[2])
+    || (R != R))
   { return fail_NaN; }
-  
-  S.x = centre[0];
-  S.y = centre[1];
-  S.z = centre[2];
-  S.R = R;
-  
+
+
+  //S.R = R;
   return 0;
 }
 
 
-
- void SpherePadder::place_virtual_spheres()
+ void SpherePadder::place_virtual_spheres() // WARNING there is a bug in this function (TODO include modifications of Philippe Marin)
 {
   
   BEGIN_FUNCTION("Place virtual spheres...");
@@ -958,6 +1134,7 @@
       if ( k < 0) k = -k;   
       if ( scalar_product < 0) k = -k;
       // TODO : il suffit de tester la valeur de mesh->face[f].normal_swap
+	  // mais pour le moment cette routine n'est pas critique (suffisemment rapide)
 	  
    
       // First virtual sphere
@@ -1101,8 +1278,8 @@
   S.R = R;
   S.type = INSERTED_BY_USER;
 
+  unsigned int inseredId = sphere.size();
   sphere.push_back(S);
-  unsigned int inseredId = sphere.size()-1;
 
   partition.locateCellOf(x-R, y-R, z-R);
   unsigned int iCellMin = partition.i_down();
@@ -1118,19 +1295,20 @@
   unsigned int id;
   Cell current_cell;
 
-  for (unsigned int i = iCellMin ; i <= iCellMax ; ++i)
+  for (unsigned int i = iCellMin ; i <= iCellMax ; ++i /*unsigned int i = 0 ; i <= partition.isize-1 ; ++i*/)
   {
-	for (unsigned int j = jCellMin ; j <= jCellMax ; ++j)
+	for (unsigned int j = jCellMin ; j <= jCellMax ; ++j /*unsigned int j = 0 ; j <= partition.jsize-1 ; ++j*/)
 	{
-	  for (unsigned int k = kCellMin ; k <= kCellMax ; ++k)
+	  for (unsigned int k = kCellMin ; k <= kCellMax ; ++k /*unsigned int k = 0 ; k <= partition.ksize-1 ; ++k*/)
 	  {
 		current_cell = partition.get_cell(i,j,k);
+		partition.add_in_cell(inseredId,i,j,k); // FIXME could be set only in iCellMin+1 to iCellMax-1 ...
 		for (unsigned int s = 0 ; s < current_cell.sphereId.size() ; ++s)
 		{
 		  id = current_cell.sphereId[s];
-		  if (sphere[id].type != INSERTED_BY_USER && sphere[id].R > 0.0)
+		  if (sphere[id].type != INSERTED_BY_USER && sphere[id].type != VIRTUAL && sphere[id].R > 0.0)
 		  {
-			if (distance_spheres(inseredId,id) < distance_max )
+			if (distance_spheres(inseredId,id) < distance_max)
 			{
 			  sphere[id].R = 0.0;
 			}
@@ -1139,7 +1317,29 @@
 	  }
 	}
   }
-	
+
+
+//   for (/*unsigned int i = iCellMin ; i <= iCellMax ; ++i*/unsigned int i = 0 ; i <= partition.isize-1 ; ++i)
+//   {
+// 	for (/*unsigned int j = jCellMin ; j <= jCellMax ; ++j*/unsigned int j = 0 ; j <= partition.jsize-1 ; ++j)
+// 	{
+// 	  for (/*unsigned int k = kCellMin ; k <= kCellMax ; ++k*/unsigned int k = 0 ; k <= partition.ksize-1 ; ++k)
+// 	  {
+// 	
+// 		current_cell = partition.get_cell(i,j,k);
+// 		for (unsigned int s = 0 ; s < current_cell.sphereId.size() ; ++s)
+// 		{
+// 
+// 		  if (current_cell.sphereId[s] == inseredId)
+// 			cout << "Cell " << i << ", " << j << ", " << k << "   OK    -> " << current_cell.sphereId[s] << endl;
+// 
+// 		}
+// 	  }
+// 	}
+//   }
+
+
+
   
 }
 
@@ -1170,12 +1370,21 @@
             id = current_cell.sphereId[s];
             if (id != sphereId && sphere[id].R > 0.0)
             {
+			  // Virtual spheres and spheres added by user cannot be modified here
+// 			  unsigned int opt = 0x00;
+// 			  if (sphere[sphereId].type == VIRTUAL || sphere[sphereId].type == INSERTED_BY_USER) opt |= 0x01;
+// 			  if (sphere[id].type == VIRTUAL || sphere[id].type == INSERTED_BY_USER) opt |= 0x02;
+// 			  if (opt == 0x03) continue;
+			  double inv_sumR = 1.0 / (sphere[sphereId].R + sphere[id].R);
               while ( (distance = distance_spheres(sphereId,id)) < distance_max )
               {                                               
-                kfact = 1.0 + distance / (sphere[sphereId].R + sphere[id].R);
-                sphere[sphereId].R *= kfact;
-                sphere[id].R       *= kfact;
+                kfact = 1.0 + distance * inv_sumR;
+                //if (opt | 0x01) // test a revoir
+				  sphere[sphereId].R *= kfact;
+				//if (opt | 0x02)
+				  sphere[id].R       *= kfact;
               }
+			  
 			  if (sphere[id].R < rmin) sphere[id].R = 0.0;
 			  if (sphere[sphereId].R < rmin) sphere[sphereId].R = 0.0;
             }
@@ -1190,11 +1399,9 @@
 }
 
 
-// FIXME attention aux interpenetrations avec rayons nuls
- void SpherePadder::detect_overlap ()
+void SpherePadder::detect_overlap ()
 {
   BEGIN_FUNCTION("Detect overlap");
-  cerr << endl;
   Sphere S1,S2;
   unsigned int nb_overlap = 0;
   double d;
@@ -1202,7 +1409,7 @@
   for (unsigned int n = 0 ; n < sphere.size()-1 ; ++n)
   {
     S1 = sphere[ n ];
-    if ( S1.type != VIRTUAL && S1.R > rmin)
+    if ( S1.type != VIRTUAL && S1.R > rmin )
     {
       for (unsigned int t = n+1 ; t < sphere.size() ; ++t)
       {
@@ -1215,17 +1422,18 @@
           {
             cerr << "Overlap!" << endl;
             partition.locateCellOf(S1.x,S1.y,S1.z);
-            cerr << "ijk (S1) = " << partition.current_i << ", " << partition.current_j << ", " << partition.current_k << endl;
+			cerr << "  Spheres         = " << n << ", " << t << endl;
+            cerr << "  Cell ijk (S1)   = " << partition.current_i << ", " << partition.current_j << ", " << partition.current_k << endl;
             partition.locateCellOf(S2.x,S2.y,S2.z);
-            cerr << "ijk (S2) = " << partition.current_i << ", " << partition.current_j << ", " << partition.current_k << endl;
+            cerr << "  Cell ijk (S2)   = " << partition.current_i << ", " << partition.current_j << ", " << partition.current_k << endl;
             cerr << "  Types           = " << S1.type << ", " << S2.type << endl;
             cerr << "  Radii           = " << S1.R << ", " << S2.R << endl;
             cerr << "  pos S1          = " << S1.x << ", " << S1.y << ", " << S1.z << endl;
             cerr << "  pos S2          = " << S2.x << ", " << S2.y << ", " << S2.z << endl;
             cerr << "  Distance / rmin = " << d/rmin << endl;
-            cerr << "  rmin            = " << rmin << endl;
-            sphere[n].type = sphere[t].type = AT_TETRA_VERTEX;
-            sphere[n].R = sphere[t].R = 0.0;
+            //cerr << "  rmin            = " << rmin << endl;
+            //sphere[n].type = sphere[t].type = AT_TETRA_VERTEX;
+            //sphere[n].R = sphere[t].R = 0.0;
             ++(nb_overlap);
           }
         }
@@ -1275,7 +1483,6 @@
   volume_portion4 = spherical_triangle(point4, point1, point2, point3);
 
   return (volume_portion1 + volume_portion2 + volume_portion3 + volume_portion4);
-  
 }
 
 // point : x,y,z,R
@@ -1319,9 +1526,72 @@
 
 }
 
+// ============================
+//           ANALISYS
+// ============================
 
+void SpherePadder::check_inProbe(unsigned int i)
+{
+  if (!probeIsDefined)    return;
+  if (sphere[i].R <= 0.0) return;
+  
+  double dx = sphere[i].x - xProbe;
+  double dy = sphere[i].y - yProbe;
+  double dz = sphere[i].z - zProbe;
+  double squared_distance = dx*dx + dy*dy + dz*dz;
+  if (squared_distance + sphere[i].R*sphere[i].R < RProbe * RProbe) sphereInProbe.push_back(i);
+}
 
+void SpherePadder::add_spherical_probe(double Rfact)
+{
+  double xmin,xmax;
+  double ymin,ymax;
+  double zmin,zmax;
+  double R;
+  
+  xmin=xmax=mesh->node[0].x;
+  ymin=ymax=mesh->node[0].y;
+  zmin=zmax=mesh->node[0].z;
+  for (unsigned int i = 1 ; i < mesh->node.size() ; ++i)
+  {
+	xmin = (xmin > mesh->node[i].x) ? mesh->node[i].x : xmin;
+	xmax = (xmax < mesh->node[i].x) ? mesh->node[i].x : xmax;
+	ymin = (ymin > mesh->node[i].y) ? mesh->node[i].y : ymin;
+	ymax = (ymax < mesh->node[i].y) ? mesh->node[i].y : ymax;
+	zmin = (zmin > mesh->node[i].z) ? mesh->node[i].z : zmin;
+	zmax = (zmax < mesh->node[i].z) ? mesh->node[i].z : zmax;
+  }
+  xProbe = 0.5 * (xmin + xmax);
+  yProbe = 0.5 * (ymin + ymax);
+  zProbe = 0.5 * (zmin + zmax);
+  RProbe = (xmax - xmin);
+  RProbe = (RProbe < (R = ymax - ymin)) ? RProbe : R;
+  RProbe = (RProbe < (R = zmax - zmin)) ? RProbe : R;
+  RProbe *= 0.5 * Rfact;
+  probeIsDefined = true;
+  compacity_file.open("compacity.dat");
+}
 
+double SpherePadder::compacity_in_probe(unsigned int ninsered)
+{
+  if (!probeIsDefined) return -1.0;
+  
+  double dr = 0.0;
+  double Vs = 0.0;
+  double fact = 1.333333333 * M_PI;
+  for (unsigned int i = 1 ; i < sphereInProbe.size() ; ++i)
+  {
+	Vs += fact * sphere[i].R * sphere[i].R * sphere[i].R;
+  }
+  
+  // TODO ameliorer cette fonction en prennant en compte les spheres coupees...
+  
+  dr = Vs / (fact*RProbe*RProbe*RProbe);
+  compacity_file << ninsered << ' ' << dr << endl;
+  return (dr);
+}
 
 
 
+
+

Modified: trunk/extra/SpherePadder/SpherePadder.hpp
===================================================================
--- trunk/extra/SpherePadder/SpherePadder.hpp	2009-04-06 10:26:50 UTC (rev 1746)
+++ trunk/extra/SpherePadder/SpherePadder.hpp	2009-04-06 15:42:25 UTC (rev 1747)
@@ -16,7 +16,7 @@
 #include <time.h>
 #include <set>
 
-# define BEGIN_FUNCTION(arg) if (trace_functions) cerr << (arg) << "... " << flush
+# define BEGIN_FUNCTION(arg) if (trace_functions) cerr << (arg) << "..." << endl << flush
 # define END_FUNCTION        if (trace_functions) cerr << "Done\n" << flush
 
 enum SphereType {AT_NODE, AT_SEGMENT, AT_FACE, AT_TETRA_CENTER, AT_TETRA_VERTEX, INSERTED_BY_USER, FROM_TRIANGULATION, VIRTUAL};
@@ -25,7 +25,7 @@
 {
   double        x,y,z,R;
   SphereType    type; 
-  unsigned int  tetraOwner;
+  unsigned int  tetraOwner; // FIXME can be removed ??
 };
 
 struct Neighbor
@@ -62,12 +62,16 @@
   protected:
                 
 	vector<vector<unsigned int> > combination;// FIXME long ?
-    SpherePackingTriangulation    triangulation;// TODO use Delaunay Triangulation to avoid flat tetrahedra
+    SpherePackingTriangulation    triangulation;
     vector<tetra_porosity>        tetra_porosities;
     
 	double       distance_spheres (unsigned int i, unsigned int j);// FIXME long ?
+	double       distance_spheres (Sphere& S1,Sphere& S2);
+	double       squared_distance_centre_spheres(unsigned int i, unsigned int j);
     double       distance_centre_spheres(Sphere& S1, Sphere& S2);
     double       distance_vector3 (double V1[],double V2[]);
+	void         build_sorted_list_of_neighbors(unsigned int sphereId, vector<neighbor_with_distance> & neighbor);
+	void         build_sorted_list_of_neighbors(Sphere & S, vector<neighbor_with_distance> & neighbor);
     double       spherical_triangle (double point1[],double point2[],double point3[],double point4[]);
     double       solid_volume_of_tetrahedron(Sphere& S1, Sphere& S2, Sphere& S3, Sphere& S4);
     void         place_at_nodes ();
@@ -76,20 +80,20 @@
     void         place_at_tetra_centers ();
     void         place_at_tetra_vertexes ();
     void         cancel_overlaps ();
+	unsigned int iter_densify(unsigned int nb_check = 100);
+	void         repack_null_radii();
     
-    
-    // 
+    // some key functions 
 	unsigned int place_fifth_sphere(unsigned int s1, unsigned int s2, unsigned int s3, unsigned int s4, Sphere& S);// FIXME long ?
-	unsigned int place_sphere_4contacts (unsigned int sphereId, unsigned int nb_combi_max = 30);// FIXME long ?
-    
-    // Check functions
-    void         detect_overlap ();
-    
+	unsigned int place_sphere_4contacts (unsigned int sphereId, unsigned int nb_combi_max = 15);// FIXME long ?
+	unsigned int check_overlaps(Sphere & S, unsigned int excludedId);
+	
     double       rmin,rmax,rmoy,dr;
-    double       ratio;
+    double       ratio; // rmax/rmin
     double       max_overlap_rate;
     unsigned int n1,n2,n3,n4,n5,n_densify;
     unsigned int nb_iter_max;
+	bool         RadiusDataIsOK,RadiusIsSet;
         
     TetraMesh *      mesh;
     vector <Sphere>  sphere;
@@ -111,17 +115,28 @@
   public:
    
     bool meshIsPlugged;
-   
+
+	void setRadiusRatio(double r);
+	void setRadiusRange(double min, double max);
+	void setMaxOverlapRate(double r) { max_overlap_rate = fabs(r); }
+	void setVirtualRadiusFactor(double f) {virtual_radius_factor = fabs(f);}
+	void setTargetSolidFraction(double sf)
+	{
+	  // TODO
+	}
+	
     void plugTetraMesh (TetraMesh * mesh);
     void save_mgpost (const char* name);
-    void save_Rxyz   (const char* name);
+	void save_tri_mgpost (const char* name);
+    void save_Rxyz (const char* name);
         
     double virtual_radius_factor;
     
     SpherePadder();
-        
-    // Pading functions
 
+	// Check functions (to debug)
+	void detect_overlap ();
+
 	//! \brief 5-step padding (for details see Jerier et al.)
     void pad_5 ();
 

Modified: trunk/extra/SpherePadder/main.cpp
===================================================================
--- trunk/extra/SpherePadder/main.cpp	2009-04-06 10:26:50 UTC (rev 1746)
+++ trunk/extra/SpherePadder/main.cpp	2009-04-06 15:42:25 UTC (rev 1747)
@@ -10,8 +10,6 @@
 
 #include "SpherePadder.hpp"
 
-#define DEBUG
-
 unsigned int           mesh_format;
 vector <unsigned int>  output_format;
 char                   mesh_file_name[100];
@@ -20,7 +18,7 @@
 
 int main()
 { 
-#ifdef DEBUG
+#if 1
  
   TetraMesh * mesh = new TetraMesh();
   //mesh->read_gmsh("meshes/cube1194.msh");
@@ -28,14 +26,19 @@
   //mesh->write_surface_MGP ("cube.mgp");
 
   SpherePadder * padder = new SpherePadder();
+  
   padder->plugTetraMesh(mesh);
-  //padder->add_spherical_probe(0.7);
-        
+  padder->setRadiusRatio(4.0);
+  padder->setMaxOverlapRate(1.0e-4);
+  padder->setVirtualRadiusFactor(100.0);
+  
   padder->pad_5();
-  padder->insert_sphere(0.5,0.5,0.5,0.2);
   padder->place_virtual_spheres();
+  padder->insert_sphere(0.5,0.5,0.5,0.4);
   padder->densify();
-  
+  padder->detect_overlap ();
+
+  //padder->save_tri_mgpost("triangulation.mgp");
   padder->save_mgpost("mgp.out.001");
   padder->save_Rxyz("spheres.Rxyz");
   return 0;