MechSys  1.0
Computing library for simulations in continuum and discrete mechanics
/home/dorival/mechsys/lib/dem/domain.h
Go to the documentation of this file.
00001 /************************************************************************
00002  * MechSys - Open Library for Mechanical Systems                        *
00003  * Copyright (C) 2005 Dorival M. Pedroso, Raul Durand                   *
00004  * Copyright (C) 2009 Sergio Galindo                                    *
00005  *                                                                      *
00006  * This program is free software: you can redistribute it and/or modify *
00007  * it under the terms of the GNU General Public License as published by *
00008  * the Free Software Foundation, either version 3 of the License, or    *
00009  * any later version.                                                   *
00010  *                                                                      *
00011  * This program is distributed in the hope that it will be useful,      *
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
00014  * GNU General Public License for more details.                         *
00015  *                                                                      *
00016  * You should have received a copy of the GNU General Public License    *
00017  * along with this program. If not, see <http://www.gnu.org/licenses/>  *
00018  ************************************************************************/
00019 
00022 #ifndef MECHSYS_DEM_DOMAIN_H
00023 #define MECHSYS_DEM_DOMAIN_H
00024 
00025 // Std lib
00026 #include <cmath>
00027 #include <stdlib.h> // for M_PI
00028 #include <iostream>
00029 #include <fstream>
00030 #include <set>
00031 #include <list>
00032 
00033 // Hdf5
00034 #ifdef USE_HDF5
00035 #include <hdf5.h>
00036 #include <hdf5_hl.h>
00037 #endif
00038 
00039 // Voro++
00040 #include "src/voro++.cc"
00041 
00042 // MechSys
00043 #include <mechsys/dem/interacton.h>
00044 #include <mechsys/util/array.h>
00045 #include <mechsys/util/util.h>
00046 #include <mechsys/util/numstreams.h>
00047 #include <mechsys/mesh/mesh.h>
00048 #include <mechsys/util/maps.h>
00049 #include <mechsys/util/stopwatch.h>
00050 #include <mechsys/util/tree.h>
00051 
00052 namespace DEM
00053 {
00054 
00055 #ifdef USE_THREAD
00056 void GlobalForce(Array<Interacton *> * I, double dt, size_t n, size_t Np)
00057 {
00058     size_t Ni = I->Size()/Np;
00059     size_t In = n*Ni;
00060     size_t Fn;
00061     n == Np-1 ? Fn = I->Size() : Fn = (n+1)*Ni;
00062     for (size_t i=In;i<Fn;i++)
00063     {
00064         (*I)[i]->CalcForce(dt);
00065     }
00066 }
00067 
00068 void GlobalMove(Array<Particle *> * P, double dt, double & MaxD, size_t n, size_t Np)
00069 {
00070     size_t Ni = P->Size()/Np;
00071     size_t In = n*Ni;
00072     size_t Fn;
00073     n == Np-1 ? Fn = P->Size() : Fn = (n+1)*Ni;
00074     MaxD      = 0.0;
00075     for (size_t i=In;i<Fn;i++)
00076     {
00077         (*P)[i]->Translate(dt);
00078         (*P)[i]->Rotate(dt);
00079         //double temp = (*P)[i]->MaxDisplacement();
00080         //if (temp > MaxD) MaxD = temp;
00081 
00082     }
00083     //std::cout << MaxD << " mu  " << n << std::endl;
00084 }
00085 
00086 #endif
00087 
00088 
00089     
00090 class Domain
00091 {
00092 public:
00093     // typedefs
00094     typedef void (*ptFun_t) (Domain & Dom, void * UserData);
00095 
00096     // Constructor
00097     Domain(void * UserData=NULL);
00098 
00099     // Destructor
00100     ~Domain();
00101 
00102     // Particle generation
00103     void GenSpheres      (int Tag, double L, size_t N, double rho, char const * Type,
00104     size_t Randomseed, double fraction, double RminFraction = 1.0);                                                              
00105     void GenRice         (int Tag, double L, size_t N, double R, double rho, size_t Randomseed, double fraction);                
00106     void GenBox          (int InitialTag, double Lx, double Ly, double Lz, double R, double Cf, bool Cohesion=false);            
00107     void GenOpenBox      (int InitialTag, double Lx, double Ly, double Lz, double R, double Cf);                                 
00108     void GenBoundingBox  (int InitialTag, double R, double Cf,bool Cohesion=false);                                              
00109     void GenBoundingPlane(int InitialTag, double R, double Cf,bool Cohesion=false);                                              
00110     void GenFromMesh     (Mesh::Generic & M, double R, double rho, bool cohesion=false, bool MC=true, double thickness = 0.0);   
00111     void AddVoroPack     (int Tag, double R, double Lx, double Ly, double Lz, size_t nx, size_t ny, size_t nz,
00112     double rho, bool Cohesion, bool Periodic,size_t Randomseed, double fraction, Vec3_t q = OrthoSys::O);                                  
00113     // Single particle addition
00114     void AddSphere   (int Tag, Vec3_t const & X, double R, double rho);                                                          
00115     void AddCube     (int Tag, Vec3_t const & X, double R, double L, double rho, double Angle=0, Vec3_t * Axis=NULL);            
00116     void AddTetra    (int Tag, Vec3_t const & X, double R, double L, double rho, double Angle=0, Vec3_t * Axis=NULL);            
00117     void AddDrill    (int Tag, Vec3_t const & X, double R, double Lt, double Ll, double rho);                                    
00118     void AddRice     (int Tag, Vec3_t const & X, double R, double L, double rho, double Angle=0, Vec3_t * Axis=NULL);            
00119     void AddPlane    (int Tag, Vec3_t const & X, double R, double Lx,double Ly, double rho, double Angle=0, Vec3_t * Axis=NULL); 
00120     void AddVoroCell (int Tag, voronoicell_neighbor & VC, double R, double rho, bool Erode, iVec3_t nv = iVec3_t(1,1,1));                  
00121     void AddTorus    (int Tag, Vec3_t const & X, Vec3_t const & N, double Rmax, double R, double rho);                           
00122     void AddCylinder (int Tag, Vec3_t const & X0, double R0, Vec3_t const & X1, double R1, double R, double rho);                
00123 
00124     // Methods
00125     void SetProps          (Dict & D);                                                                          
00126     void Initialize        (double dt=0.0);                                                                     
00127     void Solve             (double tf, double dt, double dtOut, ptFun_t ptSetup=NULL, ptFun_t ptReport=NULL,
00128                             char const * FileKey=NULL, bool RenderVideo=true, size_t Nproc=1);                  
00129     void WritePOV          (char const * FileKey);                                                              
00130     void WriteBPY          (char const * FileKey);                                                              
00131 #ifdef USE_HDF5    
00132     void Save              (char const * FileKey);                                                              
00133     void Load              (char const * FileKey);                                                              
00134 #endif
00135     void BoundingBox       (Vec3_t & minX, Vec3_t & maxX);                                                      
00136     void Center            (Vec3_t C = Vec3_t(0.0,0.0,0.0));                                                    
00137     void ResetInteractons  ();                                                                                  
00138     void ResetDisplacements();                                                                                  
00139     double MaxDisplacement ();                                                                                  
00140     void ResetContacts     ();                                                                                  
00141     void EnergyOutput      (size_t IdxOut, std::ostream & OutFile);                                             
00142     void GetGSD            (Array<double> & X, Array<double> & Y, Array<double> & D, size_t NDiv=10) const;     
00143     void Clusters          ();                                                                                  
00144     void DelParticles      (Array<int> const & Tags);                                                           
00145 
00146     // Access methods
00147     Particle       * GetParticle  (int Tag, bool Check=true);       
00148     Particle const & GetParticle  (int Tag, bool Check=true) const; 
00149     void             GetParticles (int Tag, Array<Particle*> & P);  
00150 
00151     // Auxiliar methods
00152     void   LinearMomentum  (Vec3_t & L);                    
00153     void   AngularMomentum (Vec3_t & L);                    
00154     double CalcEnergy      (double & Ekin, double & Epot);  
00155 
00156     // Data
00157     bool                                              Initialized;                 
00158     bool                                              Finished;                    
00159     Array<Particle*>                                  Particles;                   
00160     Array<Interacton*>                                Interactons;                 
00161     Array<CInteracton*>                               CInteractons;                
00162     Array<BInteracton*>                               BInteractons;                
00163     Vec3_t                                            CamPos;                      
00164     double                                            Time;                        
00165     double                                            Evis;                        
00166     double                                            Efric;                       
00167     double                                            Wext;                        
00168     double                                            Vs;                          
00169     double                                            Ms;                          
00170     double                                            Alpha;                       
00171     void *                                            UserData;                    
00172     String                                            FileKey;                     
00173     size_t                                            idx_out;                     
00174     set<pair<Particle *, Particle *> >                Listofpairs;                 
00175     Array<Array <int> >                               Listofclusters;              
00176 
00177 #ifdef USE_BOOST_PYTHON
00178     void PyAddSphere (int Tag, BPy::tuple const & X, double R, double rho)                                                         { AddSphere (Tag,Tup2Vec3(X),R,rho); }
00179     void PyAddCube   (int Tag, BPy::tuple const & X, double R, double L, double rho, double Ang, BPy::tuple const & Ax)            { Vec3_t a(Tup2Vec3(Ax)); AddCube  (Tag,Tup2Vec3(X),R,L,rho,Ang,&a); }
00180     void PyAddTetra  (int Tag, BPy::tuple const & X, double R, double L, double rho, double Ang, BPy::tuple const & Ax)            { Vec3_t a(Tup2Vec3(Ax)); AddTetra (Tag,Tup2Vec3(X),R,L,rho,Ang,&a); }
00181     void PyAddRice   (int Tag, BPy::tuple const & X, double R, double L, double rho, double Ang, BPy::tuple const & Ax)            { Vec3_t a(Tup2Vec3(Ax)); AddRice  (Tag,Tup2Vec3(X),R,L,rho,Ang,&a); }
00182     void PyAddPlane  (int Tag, BPy::tuple const & X, double R, double Lx,double Ly, double rho, double Ang, BPy::tuple const & Ax) { Vec3_t a(Tup2Vec3(Ax)); AddPlane (Tag,Tup2Vec3(X),R,Lx,Ly,rho,Ang,&a); }
00183     void PySetCamPos (BPy::tuple const & PyCamPos)                                                                                 { CamPos = Tup2Vec3(PyCamPos); }
00184     void PyGetParticles(BPy::list & P)
00185     {
00186         for (size_t i=0; i<Particles.Size(); ++i)
00187         {
00188             BPy::list p,V,E,F;
00189             double radius = Particles[i]->PyGetFeatures (V, E, F);
00190             p.append (radius);
00191             p.append (V);
00192             p.append (E);
00193             p.append (F);
00194             P.append (p);
00195         }
00196     }
00197     void PyGetGSD (BPy::list & X, BPy::list & Y, BPy::list & D, int NDiv=10)
00198     {
00199         Array<double> x, y, d;
00200         GetGSD (x, y, d, NDiv);
00201         for (size_t i=0; i<x.Size(); ++i)
00202         {
00203             X.append (x[i]);
00204             Y.append (y[i]);
00205         }
00206     }
00207 #endif
00208 
00209 };
00210 
00212 
00213 
00214 // Constructor & Destructor
00215 
00216 inline Domain::Domain (void * UD)
00217     :  Initialized(false), Time(0.0), Alpha(0.05), UserData(UD)
00218 {
00219     CamPos = 1.0, 2.0, 3.0;
00220 }
00221 
00222 inline Domain::~Domain ()
00223 {
00224     for (size_t i=0; i<Particles.Size();   ++i) if (Particles  [i]!=NULL) delete Particles  [i];
00225     for (size_t i=0; i<Interactons.Size(); ++i) if (Interactons[i]!=NULL) delete Interactons[i];
00226 }
00227 
00228 // Particle generation
00229 
00230 inline void Domain::GenSpheres (int Tag, double L, size_t N, double rho,char const * Type, size_t Randomseed, double fraction, double RminFraction)
00231 {
00232     // find radius from the edge's length
00233     Util::Stopwatch stopwatch;
00234     printf("\n%s--- Generating packing of spheres -----------------------------------------------%s\n",TERM_CLR1,TERM_RST);
00235     srand(Randomseed);
00236     double R = L/(2.0*N);
00237     if (strcmp(Type,"Normal")==0)
00238     {
00239         for (size_t n=0; n<N*N*N; ++n) 
00240         {
00241             Vec3_t pos(-L/2.0+R, -L/2.0+R, -L/2.0+R);
00242             size_t i = (n%N);
00243             size_t j = (n/N)%N;
00244             size_t k = (n/(N*N));
00245             pos += Vec3_t(2.0*i*R, 2.0*j*R, 2.0*k*R);
00246             if (rand()<fraction*RAND_MAX) AddSphere (Tag,pos,R*RminFraction+(1.0*rand())/RAND_MAX*(R-R*RminFraction),rho);
00247         }
00248     }
00249     else if (strcmp(Type,"HCP")==0)
00250     {
00251         size_t nx = N;
00252         size_t ny = int(L/(sqrt(3.0)*R));
00253         size_t nz = int(L/(sqrt(8.0/3.0)*R));
00254         for (size_t k = 0; k < nz; k++)
00255         {
00256             for (size_t j = 0; j < ny; j++)
00257             {
00258                 Vec3_t X;
00259                 if (k%2==0) X = Vec3_t(-2*R-L/2.0,R-L/2.0,2*R-L/2.0+k*sqrt(8.0/3.0)*R);
00260                 else X = Vec3_t(-R-L/2.0,R+sqrt(1.0/3.0)*R-L/2.0,2*R-L/2.0+k*sqrt(8.0/3.0)*R);
00261                 if (j%2==0) X += Vec3_t(R,j*sqrt(3.0)*R,0.0);
00262                 else X += Vec3_t(0.0,j*sqrt(3.0)*R,0.0);
00263                 for (size_t i = 0; i < nx; i++)
00264                 {
00265                     X += Vec3_t(2*R,0.0,0.0);
00266                     if (rand()<fraction*RAND_MAX) AddSphere(Tag,X,R*RminFraction+(1.0*rand())/RAND_MAX*(R-R*RminFraction),rho);
00267                 }
00268             }
00269         }
00270     }
00271     else throw new Fatal ("Right now there are only two possible packings available the Normal and the HCP, packing %s is not implemented yet",Type);
00272     printf("%s  Num of particles   = %zd%s\n",TERM_CLR2,Particles.Size(),TERM_RST);
00273 }
00274 
00275 inline void Domain::GenRice (int Tag, double L, size_t N, double R, double rho, size_t Randomseed, double fraction)
00276 {
00277     Util::Stopwatch stopwatch;
00278     printf("\n%s--- Generating packing of 'rices' -----------------------------------------------%s\n",TERM_CLR1,TERM_RST);
00279     srand(Randomseed);
00280     double dL = L/N;
00281     for (size_t n=0; n<N*N*N; ++n) 
00282     {
00283         Vec3_t pos(-L/2.0+dL, -L/2.0+dL, -L/2.0+dL);
00284         size_t i = (n%N);
00285         size_t j = (n/N)%N;
00286         size_t k = (n/(N*N));
00287         pos += Vec3_t(2.0*i*dL, 2.0*j*dL, 2.0*k*dL);
00288         if (rand()<fraction*RAND_MAX) AddRice (Tag, pos, R, dL-2*R, rho);
00289     }
00290     printf("%s  Num of particles   = %zd%s\n",TERM_CLR2,Particles.Size(),TERM_RST);
00291 }
00292 
00293 inline void Domain::GenBox (int InitialTag, double Lx, double Ly, double Lz, double R, double Cf, bool Cohesion)
00294 {
00295     /*                         +----------------+
00296      *                       ,'|              ,'|
00297      *                     ,'  |  ___       ,'  |
00298      *     z             ,'    |,'4,'  [1],'    |
00299      *     |           ,'      |~~~     ,'      |
00300      *    ,+--y      +'===============+'  ,'|   |
00301      *  x'           |   ,'|   |      |   |2|   |
00302      *               |   |3|   |      |   |,'   |
00303      *               |   |,'   +- - - | +- - - -+
00304      *               |       ,'       |       ,'
00305      *               |     ,' [0]  ___|     ,'
00306      *               |   ,'      ,'5,'|   ,'
00307      *               | ,'        ~~~  | ,'
00308      *               +----------------+'
00309      */
00310 
00311     
00312     // add faces of box
00313     Vec3_t axis0(OrthoSys::e0); // rotation of face
00314     Vec3_t axis1(OrthoSys::e1); // rotation of face
00315     size_t IIndex = Particles.Size();  // First face index
00316     AddPlane (InitialTag,   Vec3_t(Lx/2.0,0.0,0.0),  R, Cf*Lz, Cf*Ly, 1.0, M_PI/2.0, &axis1);
00317     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00318     AddPlane (InitialTag-1, Vec3_t(-Lx/2.0,0.0,0.0), R, Cf*Lz, Cf*Ly, 1.0, 3.0*M_PI/2.0, &axis1);
00319     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00320     AddPlane (InitialTag-2, Vec3_t(0.0,Ly/2.0,0.0),  R, Cf*Lx, Cf*Lz, 1.0, 3.0*M_PI/2.0, &axis0);
00321     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00322     AddPlane (InitialTag-3, Vec3_t(0.0,-Ly/2.0,0.0), R, Cf*Lx, Cf*Lz, 1.0, M_PI/2.0, &axis0);
00323     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00324     AddPlane (InitialTag-4, Vec3_t(0.0,0.0,Lz/2.0),  R, Cf*Lx, Cf*Ly, 1.0);
00325     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00326     AddPlane (InitialTag-5, Vec3_t(0.0,0.0,-Lz/2.0), R, Cf*Lx, Cf*Ly, 1.0, M_PI, &axis0);
00327     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00328 
00329     // define some tolerance for comparissions
00330     if (Cohesion)
00331     {
00332         double tol1 = 1.0e-8;
00333         double tol2 = 1.0e-3;
00334         for (size_t i=0;i<IIndex;i++)
00335         {
00336             Particle * P1 = Particles[i];
00337             for (size_t j=IIndex;j<Particles.Size();j++)
00338             {
00339                 Particle * P2 = Particles[j];
00340                 for (size_t k=0;k<P1->Faces.Size();k++)
00341                 {
00342                     Face * F1 = P1->Faces[k];
00343                     Vec3_t n1,c1;
00344                     F1->Normal  (n1);
00345                     F1->Centroid(c1);
00346                     Face * F2 = P2->Faces[0];
00347                     Vec3_t n2,c2;
00348                     F2->Normal  (n2);
00349                     F2->Centroid(c2);
00350                     Vec3_t n = 0.5*(n1-n2);
00351                     n/=norm(n);
00352                     if ((fabs(dot(n1,n2)+1.0)<tol1)
00353                        &&(fabs(dot(c2-c1,n)-2*R)<tol2))
00354                     {
00355                         BInteractons.Push(new BInteracton(P1,P2,k,1));
00356                         break;
00357                     }
00358                 }
00359             }        
00360         }
00361     }
00362 }
00363 
00364 inline void Domain::GenOpenBox (int InitialTag, double Lx, double Ly, double Lz, double R, double Cf)
00365 {
00366     /*                         +----------------+
00367      *                       ,'|              ,'|
00368      *                     ,'  |  ___       ,'  |
00369      *     z             ,'    |,'N,'  [1],'    |
00370      *     |           ,'      |~~~     ,'      |
00371      *    ,+--y      +'===============+'  ,'|   |
00372      *  x'           |   ,'|   |      |   |2|   |
00373      *               |   |3|   |      |   |,'   |
00374      *               |   |,'   +- - - | +- - - -+
00375      *               |       ,'       |       ,'
00376      *               |     ,' [0]  ___|     ,'
00377      *               |   ,'      ,'4,'|   ,'
00378      *               | ,'        ~~~  | ,'
00379      *               +----------------+'
00380      */
00381 
00382 
00383     // Creates an open box without the top lid, acts as a container
00384     
00385     // add faces of box
00386     Vec3_t axis0(OrthoSys::e0); // rotation of face
00387     Vec3_t axis1(OrthoSys::e1); // rotation of face
00388     AddPlane (InitialTag,   Vec3_t(Lx/2.0,0.0,0.0),  R, Cf*Lz, Cf*Ly, 1.0, M_PI/2.0, &axis1);
00389     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00390     AddPlane (InitialTag-1, Vec3_t(-Lx/2.0,0.0,0.0), R, Cf*Lz, Cf*Ly, 1.0, 3.0*M_PI/2.0, &axis1);
00391     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00392     AddPlane (InitialTag-2, Vec3_t(0.0,Ly/2.0,0.0),  R, Cf*Lx, Cf*Lz, 1.0, 3.0*M_PI/2.0, &axis0);
00393     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00394     AddPlane (InitialTag-3, Vec3_t(0.0,-Ly/2.0,0.0), R, Cf*Lx, Cf*Lz, 1.0, M_PI/2.0, &axis0);
00395     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00396     AddPlane (InitialTag-4, Vec3_t(0.0,0.0,-Lz/2.0), R, Cf*Lx, Cf*Ly, 1.0, M_PI, &axis0);
00397     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00398 }
00399 
00400 inline void Domain::GenBoundingBox (int InitialTag, double R, double Cf,bool Cohesion)
00401 {
00402     Center();
00403     Vec3_t minX,maxX;
00404     BoundingBox(minX,maxX);
00405     GenBox(InitialTag, maxX(0)-minX(0)+2*R, maxX(1)-minX(1)+2*R, maxX(2)-minX(2)+2*R, R, Cf,Cohesion);
00406 }
00407 
00408 inline void Domain::GenBoundingPlane (int InitialTag, double R, double Cf,bool Cohesion)
00409 {
00410     Center();
00411     Vec3_t minX,maxX;
00412     BoundingBox(minX,maxX);
00413     Vec3_t axis0(OrthoSys::e0); // rotation of face
00414     Vec3_t axis1(OrthoSys::e1); // rotation of face
00415     size_t IIndex = Particles.Size();  // First face index
00416     double Lx = maxX(0)-minX(0)+2*R;
00417     double Ly = maxX(1)-minX(1)+2*R;
00418     double Lz = maxX(2)-minX(2)+2*R;
00419     AddPlane (InitialTag  , Vec3_t(0.0,Ly/2.0,0.0),  R, Cf*Lx, Cf*Lz, 1.0, 3.0*M_PI/2.0, &axis0);
00420     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00421     AddPlane (InitialTag-1, Vec3_t(0.0,-Ly/2.0,0.0), R, Cf*Lx, Cf*Lz, 1.0, M_PI/2.0, &axis0);
00422     Particles[Particles.Size()-1]->Initialize(Particles.Size()-1);
00423 
00424     // define some tolerance for comparissions
00425     if (Cohesion)
00426     {
00427         double tol1 = 1.0e-8;
00428         double tol2 = 1.0e-3;
00429         for (size_t i=0;i<IIndex;i++)
00430         {
00431             Particle * P1 = Particles[i];
00432             for (size_t j=IIndex;j<Particles.Size();j++)
00433             {
00434                 Particle * P2 = Particles[j];
00435                 for (size_t k=0;k<P1->Faces.Size();k++)
00436                 {
00437                     Face * F1 = P1->Faces[k];
00438                     Vec3_t n1,c1;
00439                     F1->Normal  (n1);
00440                     F1->Centroid(c1);
00441                     Face * F2 = P2->Faces[0];
00442                     Vec3_t n2,c2;
00443                     F2->Normal  (n2);
00444                     F2->Centroid(c2);
00445                     Vec3_t n = 0.5*(n1-n2);
00446                     n/=norm(n);
00447                     if ((fabs(dot(n1,n2)+1.0)<tol1)
00448                        &&(fabs(dot(c2-c1,n)-2*R)<tol2))
00449                     {
00450                         BInteractons.Push(new BInteracton(P1,P2,k,1));
00451                         break;
00452                     }
00453                 }
00454             }        
00455         }
00456     }
00457 }
00458 
00459 inline void Domain::GenFromMesh (Mesh::Generic & M, double R, double rho, bool Cohesion, bool MC, double thickness)
00460 {
00461     // info
00462     Util::Stopwatch stopwatch;
00463     printf("\n%s--- Generating particles from mesh ----------------------------------------------%s\n",TERM_CLR1,TERM_RST);
00464 
00465     size_t IIndex = Particles.Size();
00466 
00467     for (size_t i=0; i<M.Cells.Size(); ++i)
00468     {
00469 
00470         Array<Vec3_t> V;             // Array of vertices
00471         Array<Array <int> > E;       // Array of edges
00472         Array<Array <int> > F;       // array of faces
00473         if (M.NDim==3)
00474         {
00475             if (thickness > 0.0) throw new Fatal("Domain::GenFromMesh: Thickness should not be used in a 3D mesh");
00476             Array<Mesh::Vertex*> const & verts = M.Cells[i]->V;
00477             size_t nverts = verts.Size();
00478 
00479             // verts
00480             V.Resize(nverts);
00481             for (size_t j=0; j<nverts; ++j)
00482             {
00483                 V[j] = verts[j]->C;
00484             }
00485 
00486             // edges
00487             size_t nedges = Mesh::NVertsToNEdges3D[nverts];
00488             E.Resize(nedges);
00489             for (size_t j=0; j<nedges; ++j)
00490             {
00491                 E[j].Push (Mesh::NVertsToEdge3D[nverts][j][0]);
00492                 E[j].Push (Mesh::NVertsToEdge3D[nverts][j][1]);
00493             }
00494 
00495             size_t nfaces = Mesh::NVertsToNFaces3D[nverts];
00496             size_t nvperf = Mesh::NVertsToNVertsPerFace3D[nverts];
00497             F.Resize(nfaces);
00498             for (size_t j=0; j<nfaces; ++j)
00499             {
00500                 for (size_t k=0; k<nvperf; ++k)
00501                 {
00502                     // TODO: check if face is planar or not
00503                     F[j].Push(Mesh::NVertsToFace3D[nverts][j][k]);
00504                 }
00505             }
00506         }
00507         else if (M.NDim==2)
00508         {
00509             if (thickness <= 0.0) throw new Fatal("Domain::GenFromMesh: Thickness should be positive in a 2D mesh");
00510             Array<Mesh::Vertex*> const & verts = M.Cells[i]->V;
00511             size_t nverts = verts.Size();
00512             V.Resize(2*nverts);
00513             for (size_t j=0; j<nverts; ++j)
00514             {
00515                 V[j] = verts[j]->C;
00516                 V[j+nverts] = verts[j]->C + Vec3_t(0.0,0.0,thickness);
00517             }
00518             size_t nedges = 3*nverts;
00519             E.Resize(nedges);
00520             for (size_t j=0; j<nverts; ++j)
00521             {
00522                 E[j].Push (Mesh::NVertsToEdge2D[nverts][j][0]);
00523                 E[j].Push (Mesh::NVertsToEdge2D[nverts][j][1]);
00524                 E[j+nverts].Push (Mesh::NVertsToEdge2D[nverts][j][0]+nverts);
00525                 E[j+nverts].Push (Mesh::NVertsToEdge2D[nverts][j][1]+nverts);
00526                 E[j+2*nverts].Push(j);
00527                 E[j+2*nverts].Push(j+nverts);
00528             }
00529             size_t nfaces = nverts+2;
00530             F.Resize(nfaces);
00531             for (size_t j=0; j<nverts; ++j)
00532             {
00533                 F[j].Push (Mesh::NVertsToEdge2D[nverts][j][0]);
00534                 F[j].Push (Mesh::NVertsToEdge2D[nverts][j][1]);
00535                 F[j].Push (Mesh::NVertsToEdge2D[nverts][j][1]+nverts);
00536                 F[j].Push (Mesh::NVertsToEdge2D[nverts][j][0]+nverts);
00537                 F[nverts].Push(nverts-1-j);
00538                 F[nverts+1].Push(j+nverts);
00539             }
00540         }
00541 
00542         double vol; // volume of the polyhedron
00543         Vec3_t CM;  // Center of mass of the polyhedron
00544         Mat3_t It;  // Inertia tensor of the polyhedron
00545         PolyhedraMP(V,F,vol,CM,It);
00546         Erosion(V,E,F,R);
00547 
00548         // add particle
00549         Particles.Push (new Particle(M.Cells[i]->Tag, V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
00550         Particles[Particles.Size()-1]->Index = Particles.Size()-1;
00551         if (!MC)
00552         {
00553             Particles[Particles.Size()-1]->x       = CM;
00554             Particles[Particles.Size()-1]->Props.V = vol;
00555             Particles[Particles.Size()-1]->Props.m = vol*rho;
00556             Vec3_t I;
00557             Quaternion_t Q;
00558             Vec3_t xp,yp,zp;
00559             Eig(It,I,xp,yp,zp);
00560             CheckDestroGiro(xp,yp,zp);
00561             I *= rho;
00562             Q(0) = 0.5*sqrt(1+xp(0)+yp(1)+zp(2));
00563             Q(1) = (yp(2)-zp(1))/(4*Q(0));
00564             Q(2) = (zp(0)-xp(2))/(4*Q(0));
00565             Q(3) = (xp(1)-yp(0))/(4*Q(0));
00566             Q = Q/norm(Q);
00567             Particles[Particles.Size()-1]->I     = I;
00568             Particles[Particles.Size()-1]->Q     = Q;
00569             double Dmax = Distance(CM,V[0])+R;
00570             for (size_t i=1; i<V.Size(); ++i)
00571             {
00572                 if (Distance(CM,V[i])+R > Dmax) Dmax = Distance(CM,V[i])+R;
00573             }
00574             Particles[Particles.Size()-1]->Ekin = 0.0;
00575             Particles[Particles.Size()-1]->Erot = 0.0;
00576             Particles[Particles.Size()-1]->Dmax  = Dmax;
00577             Particles[Particles.Size()-1]->PropsReady = true;
00578         }
00579     }
00580 
00581     Array<Array <int> > Neigh(Particles.Size()-IIndex);
00582     Array<Array <int> > FNeigh(Particles.Size()-IIndex);
00583     if(Cohesion)
00584     {
00585         M.FindNeigh();
00586         //std::cout << M;
00587         for (size_t i=0; i<M.Cells.Size(); ++i) 
00588         {
00589             for (Mesh::Neighs_t::const_iterator p=M.Cells[i]->Neighs.begin(); p!=M.Cells[i]->Neighs.end(); ++p)
00590             {
00591                 Neigh[i].Push(p->second.second->ID);
00592                 FNeigh[i].Push(p->second.first);
00593             }           
00594         }
00595         for (size_t i=0; i<Neigh.Size(); ++i)
00596         {
00597             for (size_t j=0; j<Neigh[i].Size(); ++j)
00598             {
00599                 size_t index = Neigh[Neigh[i][j]].Find(i);
00600                 if ((size_t)Neigh[i][j]>i) BInteractons.Push(new BInteracton(Particles[i+IIndex],Particles[Neigh[i][j]+IIndex],FNeigh[i][j],FNeigh[Neigh[i][j]][index]));
00601             }
00602         }
00603         
00604     }
00605 
00606     // info
00607     printf("%s  Num of particles   = %zd%s\n",TERM_CLR2,Particles.Size(),TERM_RST);
00608 }
00609 
00610 inline void Domain::AddVoroPack (int Tag, double R, double Lx, double Ly, double Lz, size_t nx, size_t ny, size_t nz, double rho
00611                                  , bool Cohesion, bool Periodic,size_t Randomseed, double fraction, Vec3_t qin)
00612 {
00613     // info
00614     Util::Stopwatch stopwatch;
00615     printf("\n%s--- Adding Voronoi particles packing --------------------------------------------%s\n",TERM_CLR1,TERM_RST);
00616 
00617     srand(Randomseed);
00618     const double x_min=-(nx*Lx/2.0), x_max=nx*Lx/2.0;
00619     const double y_min=-(ny*Ly/2.0), y_max=ny*Ly/2.0;
00620     const double z_min=-(nz*Lz/2.0), z_max=nz*Lz/2.0;
00621     container con(x_min,x_max,y_min,y_max,z_min,z_max,nx,ny,nz, Periodic,Periodic,Periodic,8);
00622     int n = 0;
00623     for (size_t i=0; i<nx; i++)
00624     {
00625         for (size_t j=0; j<ny; j++)
00626         {
00627             for (size_t k=0; k<nz; k++)
00628             {
00629                 double x = x_min+(i+0.5*qin(0)+(1-qin(0))*double(rand())/RAND_MAX)*(x_max-x_min)/nx;
00630                 double y = y_min+(j+0.5*qin(1)+(1-qin(1))*double(rand())/RAND_MAX)*(y_max-y_min)/ny;
00631                 double z = z_min+(k+0.5*qin(2)+(1-qin(2))*double(rand())/RAND_MAX)*(z_max-z_min)/nz;
00632                 con.put (n,x,y,z);
00633                 n++;
00634             }
00635         }
00636     }
00637 
00638     fpoint x,y,z,px,py,pz;
00639     container *cp = & con;
00640     voropp_loop l1(cp);
00641     int q,s;
00642     voronoicell_neighbor c;
00643     s=l1.init(con.ax,con.bx,con.ay,con.by,con.az,con.bz,px,py,pz);
00644 
00645     Array<Array <size_t> > ListBpairs(n);
00646     size_t IIndex = Particles.Size();
00647     do 
00648     {
00649         for(q=0;q<con.co[s];q++) 
00650         {
00651             x=con.p[s][con.sz*q]+px;y=con.p[s][con.sz*q+1]+py;z=con.p[s][con.sz*q+2]+pz;
00652             if(x>con.ax&&x<con.bx&&y>con.ay&&y<con.by&&z>con.az&&z<con.bz) 
00653             {
00654                 if(con.compute_cell(c,l1.ip,l1.jp,l1.kp,s,q,x,y,z)) 
00655                 {
00656 
00657                     if (rand()<fraction*RAND_MAX)
00658                     {
00659                         AddVoroCell(Tag,c,R,rho,true,iVec3_t(nx,ny,nz));
00660                         Vec3_t trans(x/nx,y/ny,z/nz);
00661                         Particle * P = Particles[Particles.Size()-1];
00662                         P->Translate(trans);
00663                     }
00664                 }
00665             }
00666         }
00667     } while((s=l1.inc(px,py,pz))!=-1);
00668 
00669     // info
00670     printf("%s  Num of particles   = %zd%s\n",TERM_CLR2,Particles.Size(),TERM_RST);
00671 
00672 
00673     if (Cohesion)
00674     {
00675         //if (fraction<1.0) throw new Fatal("Domain::AddVoroPack: With the Cohesion all particles should be considered, plese change the fraction to 1.0");
00676 
00677         // define some tolerance for comparissions
00678         double tol1 = 1.0e-8;
00679         double tol2 = 1.0e-3;
00680         for (size_t i=IIndex;i<Particles.Size()-1;i++)
00681         {
00682             Particle * P1 = Particles[i];
00683             for (size_t j=i+1;j<Particles.Size();j++)
00684             {
00685                 Particle * P2 = Particles[j];
00686                 if (Distance(P1->x,P2->x)<P1->Dmax+P2->Dmax)
00687                 {
00688                     for (size_t k=0;k<P1->Faces.Size();k++)
00689                     {
00690                         Face * F1 = P1->Faces[k];
00691                         Vec3_t n1,c1;
00692                         F1->Normal  (n1);
00693                         F1->Centroid(c1);
00694                         bool found = false;
00695                         for (size_t l=0;l<P2->Faces.Size();l++)
00696                         {
00697                             Face * F2 = P2->Faces[l];
00698                             Vec3_t n2,c2;
00699                             F2->Normal  (n2);
00700                             F2->Centroid(c2);
00701                             Vec3_t n = 0.5*(n1-n2);
00702                             n/=norm(n);
00703                             if ((fabs(dot(n1,n2)+1.0)<tol1)
00704                                &&(fabs(Distance(c1,*F2)-2*R)<tol2)
00705                                &&(fabs(Distance(c2,*F1)-2*R)<tol2))
00706                             {
00707                                 BInteractons.Push(new BInteracton(P1,P2,k,l));
00708                                 found = true;
00709                                 break;
00710                             }
00711                         }
00712                         if (found) break;
00713                     }
00714                 }
00715             }
00716         }
00717     }
00718 }
00719 
00720 // Single particle addition
00721 
00722 inline void Domain::AddSphere (int Tag,Vec3_t const & X, double R, double rho)
00723 {
00724     // vertices
00725     Array<Vec3_t> V(1);
00726     V[0] = X;
00727 
00728     // edges
00729     Array<Array <int> > E(0); // no edges
00730 
00731     // faces
00732     Array<Array <int> > F(0); // no faces
00733 
00734     // add particle
00735     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
00736 }
00737 
00738 inline void Domain::AddCube (int Tag, Vec3_t const & X, double R, double L, double rho, double Angle, Vec3_t * Axis)
00739 {
00740     // vertices
00741     Array<Vec3_t> V(8);
00742     double l = L/2.0;
00743     V[0] = -l, -l, -l;
00744     V[1] =  l, -l, -l;
00745     V[2] =  l,  l, -l;
00746     V[3] = -l,  l, -l;
00747     V[4] = -l, -l,  l;
00748     V[5] =  l, -l,  l;
00749     V[6] =  l,  l,  l;
00750     V[7] = -l,  l,  l;
00751 
00752     // edges
00753     Array<Array <int> > E(12);
00754     for (size_t i=0; i<12; ++i) E[i].Resize(2);
00755     E[ 0] = 0, 1;
00756     E[ 1] = 1, 2;
00757     E[ 2] = 2, 3;
00758     E[ 3] = 3, 0;
00759     E[ 4] = 4, 5;
00760     E[ 5] = 5, 6;
00761     E[ 6] = 6, 7;
00762     E[ 7] = 7, 4;
00763     E[ 8] = 0, 4;
00764     E[ 9] = 1, 5;
00765     E[10] = 2, 6;
00766     E[11] = 3, 7;
00767 
00768     // faces
00769     Array<Array <int> > F(6);
00770     for (size_t i=0; i<6; i++) F[i].Resize(4);
00771     F[0] = 4, 7, 3, 0;
00772     F[1] = 1, 2, 6, 5;
00773     F[2] = 0, 1, 5, 4;
00774     F[3] = 2, 3, 7, 6;
00775     F[4] = 0, 3, 2, 1;
00776     F[5] = 4, 5, 6, 7;
00777 
00778     // calculate the rotation
00779     bool ThereisanAxis = true;
00780     if (Axis==NULL)
00781     {
00782         Angle   = (1.0*rand())/RAND_MAX*2*M_PI;
00783         Axis = new Vec3_t((1.0*rand())/RAND_MAX, (1.0*rand())/RAND_MAX, (1.0*rand())/RAND_MAX);
00784         ThereisanAxis = false;
00785     }
00786     Quaternion_t q;
00787     NormalizeRotation (Angle,(*Axis),q);
00788     for (size_t i=0; i<V.Size(); i++)
00789     {
00790         Vec3_t t;
00791         Rotation (V[i],q,t);
00792         V[i] = t+X;
00793     }
00794 
00795     // add particle
00796     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
00797 
00798     // clean up
00799     if (!ThereisanAxis) delete Axis;
00800     q(0) = 1.0;
00801     q(1) = 0.0;
00802     q(2) = 0.0;
00803     q(3) = 0.0;
00804     q = q/norm(q);
00805 
00806     Particles[Particles.Size()-1]->Q          = q;
00807     Particles[Particles.Size()-1]->Props.V    = L*L*L;
00808     Particles[Particles.Size()-1]->Props.m    = rho*L*L*L;
00809     Particles[Particles.Size()-1]->I          = L*L, L*L, L*L;
00810     Particles[Particles.Size()-1]->I         *= Particles[Particles.Size()-1]->Props.m/6.0;
00811     Particles[Particles.Size()-1]->x          = X;
00812     Particles[Particles.Size()-1]->Ekin       = 0.0;
00813     Particles[Particles.Size()-1]->Erot       = 0.0;
00814     Particles[Particles.Size()-1]->Dmax       = sqrt(3.0*L*L/4.0)+R;
00815     Particles[Particles.Size()-1]->PropsReady = true;
00816     Particles[Particles.Size()-1]->Index      = Particles.Size()-1;
00817     
00818 
00819 }
00820 
00821 inline void Domain::AddTetra (int Tag, Vec3_t const & X, double R, double L, double rho, double Angle, Vec3_t * Axis)
00822 {
00823     // vertices
00824     double sq8 = sqrt(8.0);
00825     Array<Vec3_t> V(4);
00826     V[0] =  L/sq8,  L/sq8, L/sq8;
00827     V[1] = -L/sq8, -L/sq8, L/sq8;
00828     V[2] = -L/sq8,  L/sq8,-L/sq8;
00829     V[3] =  L/sq8, -L/sq8,-L/sq8;
00830 
00831     // edges
00832     Array<Array <int> > E(6);
00833     for (size_t i=0; i<6; ++i) E[i].Resize(2);
00834     E[0] = 0, 1;
00835     E[1] = 1, 2;
00836     E[2] = 2, 0;
00837     E[3] = 0, 3;
00838     E[4] = 1, 3;
00839     E[5] = 2, 3;
00840 
00841     // face
00842     Array<Array <int> > F;
00843     F.Resize(4);
00844     for (size_t i=0; i<4; ++i) F[i].Resize(3);
00845     F[0] = 0, 3, 2;
00846     F[1] = 0, 1, 3;
00847     F[2] = 0, 2, 1;
00848     F[3] = 1, 2, 3;
00849 
00850     // calculate the rotation
00851     bool ThereisanAxis = true;
00852     if (Axis==NULL)
00853     {
00854         Angle   = (1.0*rand())/RAND_MAX*2*M_PI;
00855         Axis = new Vec3_t((1.0*rand())/RAND_MAX, (1.0*rand())/RAND_MAX, (1.0*rand())/RAND_MAX);
00856         ThereisanAxis = false;
00857     }
00858     Quaternion_t q;
00859     NormalizeRotation (Angle,(*Axis),q);
00860     for (size_t i=0; i<V.Size(); i++)
00861     {
00862         Vec3_t t;
00863         Rotation (V[i],q,t);
00864         V[i] = t+X;
00865     }
00866 
00867     // add particle
00868     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
00869 
00870     // clean up
00871     if (!ThereisanAxis) delete Axis;
00872     q(0) = 1.0;
00873     q(1) = 0.0;
00874     q(2) = 0.0;
00875     q(3) = 0.0;
00876     q = q/norm(q);
00877 
00878     Particles[Particles.Size()-1]->Q          = q;
00879     Particles[Particles.Size()-1]->Props.V    = sqrt(2.0)*L*L*L/12.0;
00880     Particles[Particles.Size()-1]->Props.m    = rho*sqrt(2.0)*L*L*L/12.0;
00881     Particles[Particles.Size()-1]->I          = L*L, L*L, L*L;
00882     Particles[Particles.Size()-1]->I         *= Particles[Particles.Size()-1]->Props.m/20.0;
00883     Particles[Particles.Size()-1]->x          = X;
00884     Particles[Particles.Size()-1]->Ekin       = 0.0;
00885     Particles[Particles.Size()-1]->Erot       = 0.0;
00886     Particles[Particles.Size()-1]->Dmax       = sqrt(3.0*L*L/8.0)+R;
00887     Particles[Particles.Size()-1]->PropsReady = true;
00888     Particles[Particles.Size()-1]->Index      = Particles.Size()-1;
00889 }
00890 
00891 inline void Domain::AddDrill (int Tag, const Vec3_t & X, double R, double Lt, double Ll, double rho)
00892 {
00893     Array<Vec3_t> V(9);
00894     V[0] =  Lt/2.0,  Lt/2.0, Ll/2.0;
00895     V[1] = -Lt/2.0,  Lt/2.0, Ll/2.0;
00896     V[2] = -Lt/2.0, -Lt/2.0, Ll/2.0;
00897     V[3] =  Lt/2.0, -Lt/2.0, Ll/2.0;
00898     V[4] =  Lt/2.0,  Lt/2.0,    0.0;
00899     V[5] = -Lt/2.0,  Lt/2.0,    0.0;
00900     V[6] = -Lt/2.0, -Lt/2.0,    0.0;
00901     V[7] =  Lt/2.0, -Lt/2.0,    0.0;
00902     V[8] =     0.0,     0.0,-Ll/2.0;
00903     
00904     Array<Array <int> > E(12);
00905     for (size_t i=0; i<12; ++i) E[i].Resize(2);
00906     for (size_t i=0;i<4;i++)
00907     {
00908         E[i]   = i  , (i+1)%4    ;
00909         E[i+4] = i+4, (i+5)%4 + 4;
00910         E[i+8] = i+4, 8;
00911     }
00912 
00913     Array<Array <int> > F;
00914     F.Resize(9);
00915     F[0].Resize(4);
00916     F[0] = 0, 1, 2, 3;
00917     F[1].Resize(4);
00918     F[1] = 0, 4, 5, 1;
00919     F[2].Resize(4);
00920     F[2] = 1, 5, 6, 2;
00921     F[3].Resize(4);
00922     F[3] = 2, 6, 7, 3;
00923     F[4].Resize(4);
00924     F[4] = 3, 7, 4, 0;
00925     F[5].Resize(3);
00926     F[5] = 4, 8, 5;
00927     F[6].Resize(3);
00928     F[6] = 5, 8, 6;
00929     F[7].Resize(3);
00930     F[7] = 6, 8, 7;
00931     F[8].Resize(3);
00932     F[8] = 7, 8, 4;
00933 
00934 
00935     double vol; // volume of the polyhedron
00936     Vec3_t CM;  // Center of mass of the polyhedron
00937     Mat3_t It;  // Inertia tensor of the polyhedron
00938     PolyhedraMP(V,F,vol,CM,It);
00939     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
00940     Particles[Particles.Size()-1]->x       = CM;
00941     Particles[Particles.Size()-1]->Props.V = vol;
00942     Particles[Particles.Size()-1]->Props.m = vol*rho;
00943     Vec3_t I;
00944     Quaternion_t Q;
00945     Vec3_t xp,yp,zp;
00946     Eig(It,I,xp,yp,zp);
00947     CheckDestroGiro(xp,yp,zp);
00948     I *= rho;
00949     Q(0) = 0.5*sqrt(1+xp(0)+yp(1)+zp(2));
00950     Q(1) = (yp(2)-zp(1))/(4*Q(0));
00951     Q(2) = (zp(0)-xp(2))/(4*Q(0));
00952     Q(3) = (xp(1)-yp(0))/(4*Q(0));
00953     Q = Q/norm(Q);
00954     Particles[Particles.Size()-1]->I     = I;
00955     Particles[Particles.Size()-1]->Q     = Q;
00956     double Dmax = Distance(CM,V[0])+R;
00957     for (size_t i=1; i<V.Size(); ++i)
00958     {
00959         if (Distance(CM,V[i])+R > Dmax) Dmax = Distance(CM,V[i])+R;
00960     }
00961     Particles[Particles.Size()-1]->Ekin = 0.0;
00962     Particles[Particles.Size()-1]->Erot = 0.0;
00963     Particles[Particles.Size()-1]->Dmax  = Dmax;
00964     Particles[Particles.Size()-1]->PropsReady = true;
00965     Particles[Particles.Size()-1]->Index = Particles.Size()-1;
00966 
00967     Vec3_t Y = X;
00968     Particles[Particles.Size()-1]->Translate(Y);
00969 
00970 }
00971 
00972 inline void Domain::AddRice (int Tag, const Vec3_t & X, double R, double L, double rho, double Angle, Vec3_t * Axis)
00973 {
00974     // vertices
00975     Array<Vec3_t> V(2);
00976     V[0] = 0.0, 0.0,  L/2;
00977     V[1] = 0.0, 0.0, -L/2;
00978 
00979     // edges
00980     Array<Array <int> > E(1);
00981     E[0].Resize(2);
00982     E[0] = 0, 1;
00983 
00984     // faces
00985     Array<Array <int> > F(0); // no faces
00986 
00987     // calculate the rotation
00988     bool ThereisanAxis = true;
00989     if (Axis==NULL)
00990     {
00991         Angle   = (1.0*rand())/RAND_MAX*2*M_PI;
00992         Axis = new Vec3_t((1.0*rand())/RAND_MAX, (1.0*rand())/RAND_MAX, (1.0*rand())/RAND_MAX);
00993         ThereisanAxis = false;
00994     }
00995     Quaternion_t q;
00996     NormalizeRotation (Angle,(*Axis),q);
00997     for (size_t i=0; i<V.Size(); i++)
00998     {
00999         Vec3_t t;
01000         Rotation (V[i],q,t);
01001         V[i] = t+X;
01002     }
01003 
01004     // add particle
01005     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
01006 
01007     Particles[Particles.Size()-1]->Q          = q;
01008     Particles[Particles.Size()-1]->Props.V    = (4.0/3.0)*M_PI*R*R*R + M_PI*L*R*R;
01009     Particles[Particles.Size()-1]->Props.m    = rho*Particles[Particles.Size()-1]->Props.V;
01010     Particles[Particles.Size()-1]->I          = (1.0/3.0)*M_PI*rho*R*R*R*L*L + (1.0/12.0)*M_PI*rho*R*R*L*L*L + (3.0/4.0)*M_PI*rho*R*R*R*R*L + (8.0/15.0)*M_PI*rho*R*R*R*R*R,
01011                                                 (1.0/3.0)*M_PI*rho*R*R*R*L*L + (1.0/12.0)*M_PI*rho*R*R*L*L*L + (3.0/4.0)*M_PI*rho*R*R*R*R*L + (8.0/15.0)*M_PI*rho*R*R*R*R*R,
01012                                                 0.5*M_PI*rho*R*R*R*R*L + (8.0/15.0)*M_PI*rho*R*R*R*R*R;
01013     Particles[Particles.Size()-1]->x          = X;
01014     Particles[Particles.Size()-1]->Ekin       = 0.0;
01015     Particles[Particles.Size()-1]->Erot       = 0.0;
01016     Particles[Particles.Size()-1]->Dmax       = 0.5*L + R;
01017     Particles[Particles.Size()-1]->PropsReady = true;
01018     Particles[Particles.Size()-1]->Index      = Particles.Size()-1;
01019 
01020     // clean up
01021     if (!ThereisanAxis) delete Axis;
01022 }
01023 
01024 inline void Domain::AddPlane (int Tag, const Vec3_t & X, double R, double Lx, double Ly, double rho, double Angle, Vec3_t * Axis)
01025 {
01026     // vertices
01027     Array<Vec3_t> V(4);
01028     double lx = Lx/2.0, ly = Ly/2.0;
01029     V[0] = -lx, -ly, 0.0;
01030     V[1] =  lx, -ly, 0.0;
01031     V[2] =  lx,  ly, 0.0;
01032     V[3] = -lx,  ly, 0.0;
01033 
01034     // edges
01035     Array<Array <int> > E(4);
01036     for (size_t i=0; i<4; ++i) E[i].Resize(2);
01037     E[ 0] = 0, 1;
01038     E[ 1] = 1, 2;
01039     E[ 2] = 2, 3;
01040     E[ 3] = 3, 0;
01041 
01042     // faces
01043     Array<Array <int> > F(1);
01044     F[0].Resize(4);
01045     F[0] = 0, 3, 2, 1;
01046 
01047     bool ThereisanAxis = true;
01048     if (Axis==NULL)
01049     {
01050         Angle   = 0.;
01051         Axis = new Vec3_t((1.0*rand())/RAND_MAX, (1.0*rand())/RAND_MAX, (1.0*rand())/RAND_MAX);
01052         ThereisanAxis = false;
01053     }
01054     Quaternion_t q;
01055     NormalizeRotation (Angle,(*Axis),q);
01056     for (size_t i=0; i<V.Size(); i++)
01057     {
01058         Vec3_t t;
01059         Rotation (V[i],q,t);
01060         V[i] = t+X;
01061     }
01062 
01063     // add particle
01064     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
01065     Particles[Particles.Size()-1]->Q          = q;
01066     Particles[Particles.Size()-1]->Props.V    = Lx*Ly*2*R;
01067     Particles[Particles.Size()-1]->Props.m    = rho*Lx*Ly*2*R;
01068     Particles[Particles.Size()-1]->I          = (1.0/12.0)*(Ly*Ly+4*R*R),(1.0/12.0)*(Lx*Lx+4*R*R),(1.0/12.0)*(Lx*Lx+Ly*Ly);
01069     Particles[Particles.Size()-1]->I         *= Particles[Particles.Size()-1]->Props.m;
01070     Particles[Particles.Size()-1]->x          = X;
01071     Particles[Particles.Size()-1]->Ekin       = 0.0;
01072     Particles[Particles.Size()-1]->Erot       = 0.0;
01073     Particles[Particles.Size()-1]->Dmax       = sqrt(Lx*Lx+Ly*Ly)+R;
01074     Particles[Particles.Size()-1]->PropsReady = true;
01075     Particles[Particles.Size()-1]->Index      = Particles.Size()-1;
01076     // clean up
01077     if (!ThereisanAxis) delete Axis;
01078 }
01079 
01080 inline void Domain::AddVoroCell (int Tag, voronoicell_neighbor & VC, double R, double rho, bool Erode, iVec3_t nv)
01081 {
01082     Array<Vec3_t> V(VC.p);
01083     Array<Array <int> > E;
01084     Array<int> Eaux(2);
01085     for(int i=0;i<VC.p;i++) 
01086     {
01087         V[i] = Vec3_t(0.5*VC.pts[3*i]/nv(0),0.5*VC.pts[3*i+1]/nv(1),0.5*VC.pts[3*i+2]/nv(2));
01088         for(int j=0;j<VC.nu[i];j++) 
01089         {
01090             int k=VC.ed[i][j];
01091             if (VC.ed[i][j]<i) 
01092             {
01093                 Eaux[0] = i;
01094                 Eaux[1] = k;
01095                 E.Push(Eaux);
01096             }
01097         }
01098     }
01099     Array<Array <int> > F;
01100     Array<int> Faux;
01101     for(int i=0;i<VC.p;i++) 
01102     {
01103         for(int j=0;j<VC.nu[i];j++) 
01104         {
01105             int k=VC.ed[i][j];
01106             if (k>=0) 
01107             {
01108                 Faux.Push(i);
01109                 VC.ed[i][j]=-1-k;
01110                 int l=VC.cycle_up(VC.ed[i][VC.nu[i]+j],k);
01111                 do 
01112                 {
01113                     Faux.Push(k);
01114                     int m=VC.ed[k][l];
01115                     VC.ed[k][l]=-1-m;
01116                     l=VC.cycle_up(VC.ed[k][VC.nu[k]+l],m);
01117                     k=m;
01118                 } while (k!=i);
01119                 Array<int> Faux2(Faux.Size());
01120                 for (size_t l = 0; l < Faux.Size();l++)
01121                 {
01122                     Faux2[l] = Faux[Faux.Size()-1-l];
01123                 }
01124 
01125                 F.Push(Faux2);
01126                 Faux.Clear();
01127                 Faux2.Clear();
01128             }
01129         }
01130     }
01131     VC.reset_edges();
01132     double vol; // volume of the polyhedron
01133     Vec3_t CM;  // Center of mass of the polyhedron
01134     Mat3_t It;  // Inertia tensor of the polyhedron
01135     PolyhedraMP(V,F,vol,CM,It);
01136     if (Erode) Erosion(V,E,F,R);
01137     // add particle
01138     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
01139     Particles[Particles.Size()-1]->x       = CM;
01140     Particles[Particles.Size()-1]->Props.V = vol;
01141     Particles[Particles.Size()-1]->Props.m = vol*rho;
01142     Vec3_t I;
01143     Quaternion_t Q;
01144     Vec3_t xp,yp,zp;
01145     Eig(It,I,xp,yp,zp);
01146     CheckDestroGiro(xp,yp,zp);
01147     I *= rho;
01148     Q(0) = 0.5*sqrt(1+xp(0)+yp(1)+zp(2));
01149     Q(1) = (yp(2)-zp(1))/(4*Q(0));
01150     Q(2) = (zp(0)-xp(2))/(4*Q(0));
01151     Q(3) = (xp(1)-yp(0))/(4*Q(0));
01152     Q = Q/norm(Q);
01153     Particles[Particles.Size()-1]->I     = I;
01154     Particles[Particles.Size()-1]->Q     = Q;
01155     double Dmax = Distance(CM,V[0])+R;
01156     for (size_t i=1; i<V.Size(); ++i)
01157     {
01158         if (Distance(CM,V[i])+R > Dmax) Dmax = Distance(CM,V[i])+R;
01159     }
01160     Particles[Particles.Size()-1]->Ekin = 0.0;
01161     Particles[Particles.Size()-1]->Erot = 0.0;
01162     Particles[Particles.Size()-1]->Dmax  = Dmax;
01163     Particles[Particles.Size()-1]->PropsReady = true;
01164     Particles[Particles.Size()-1]->Index = Particles.Size()-1;
01165 }
01166 
01167 inline void Domain::AddTorus (int Tag, Vec3_t const & X, Vec3_t const & N, double Rmax, double R, double rho)
01168 {
01169     // Normalize normal vector
01170     Vec3_t n = N/norm(N);
01171 
01172     // Create the 2 vertices that define the torus
01173     Vec3_t P1 = OrthoSys::e0 - dot(OrthoSys::e0,n)*n;
01174     if (norm(P1)<1.0e-12) P1 = OrthoSys::e1 - dot(OrthoSys::e1,n)*n;
01175     P1       /= norm(P1);
01176     Vec3_t P2 = cross(n,P1);
01177     P2       /= norm(P2);
01178     Array<Vec3_t > V(2);
01179     V[0] = X + Rmax*P1;
01180     V[1] = X + Rmax*P2;
01181 
01182     // the torus has no edges or faces
01183     Array<Array <int> > E(0);
01184     Array<Array <int> > F(0);
01185 
01186     //Add the particle just with two vertices
01187     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
01188 
01189     //Input all the mass properties
01190     Vec3_t xp,yp,zp;
01191     xp = P1;
01192     zp = P2;
01193     yp = cross(zp,xp);
01194     CheckDestroGiro(xp,yp,zp);
01195     Quaternion_t q;
01196     q(0) = 0.5*sqrt(1+xp(0)+yp(1)+zp(2));
01197     q(1) = (yp(2)-zp(1))/(4*q(0));
01198     q(2) = (zp(0)-xp(2))/(4*q(0));
01199     q(3) = (xp(1)-yp(0))/(4*q(0));
01200     q = q/norm(q);
01201 
01202     Particles[Particles.Size()-1]->Q          = q;
01203     Particles[Particles.Size()-1]->Props.V    = 2*M_PI*M_PI*R*R*Rmax;
01204     Particles[Particles.Size()-1]->Props.m    = rho*2*M_PI*M_PI*R*R*Rmax;
01205     Particles[Particles.Size()-1]->I          = 0.125*(4*Rmax*Rmax + 5*R*R), (Rmax*Rmax+0.75*R*R), 0.125*(4*Rmax*Rmax + 5*R*R);
01206     Particles[Particles.Size()-1]->I         *= Particles[Particles.Size()-1]->Props.m;
01207     Particles[Particles.Size()-1]->x          = X;
01208     Particles[Particles.Size()-1]->Ekin       = 0.0;
01209     Particles[Particles.Size()-1]->Erot       = 0.0;
01210     Particles[Particles.Size()-1]->Dmax       = Rmax + R;
01211     Particles[Particles.Size()-1]->PropsReady = true;
01212     Particles[Particles.Size()-1]->Index      = Particles.Size()-1;
01213     
01214     Particles[Particles.Size()-1]->Tori.Push(new Torus(&Particles[Particles.Size()-1]->x,Particles[Particles.Size()-1]->Verts[0],Particles[Particles.Size()-1]->Verts[1]));
01215 
01216 }
01217 
01218 inline void Domain::AddCylinder (int Tag, Vec3_t const & X0, double R0, Vec3_t const & X1, double R1, double R, double rho)
01219 {
01220     // Define all key variables of the cylinder
01221     Vec3_t n = X1 - X0;
01222     n /= norm(n);
01223     Vec3_t P1 = OrthoSys::e0 - dot(OrthoSys::e0,n)*n;
01224     if (norm(P1)<1.0e-12) P1 = OrthoSys::e1 - dot(OrthoSys::e1,n)*n;
01225     P1       /= norm(P1);
01226     Vec3_t P2 = cross(n,P1);
01227     P2       /= norm(P2);
01228 
01229     //The cylinder is defined by 6 vertices
01230     Array<Vec3_t > V(6);
01231     V[0] = X0 + R0*P1;
01232     V[1] = X0 + R0*P2;
01233     V[2] = X0 - R0*P1;
01234     V[3] = X1 + R1*P1;
01235     V[4] = X1 + R1*P2;
01236     V[5] = X1 - R1*P1;
01237 
01238     // It has no edges or faces
01239     Array<Array <int> > E(0);
01240     Array<Array <int> > F(0);
01241 
01242     //Add the particle just with the vertices
01243     Particles.Push (new Particle(Tag,V,E,F,OrthoSys::O,OrthoSys::O,R,rho));
01244 
01245     //Input all the mass properties
01246     Vec3_t xp,yp,zp;
01247     xp = P1;
01248     zp = P2;
01249     yp = cross(zp,xp);
01250     CheckDestroGiro(xp,yp,zp);
01251     Quaternion_t q;
01252     q(0) = 0.5*sqrt(1+xp(0)+yp(1)+zp(2));
01253     q(1) = (yp(2)-zp(1))/(4*q(0));
01254     q(2) = (zp(0)-xp(2))/(4*q(0));
01255     q(3) = (xp(1)-yp(0))/(4*q(0));
01256     q = q/norm(q);
01257 
01258     Particles[Particles.Size()-1]->Q          = q;
01259     Particles[Particles.Size()-1]->Props.V    = M_PI*R0*R0*norm(X1-X0);
01260     Particles[Particles.Size()-1]->Props.m    = rho*M_PI*R0*R0*norm(X1-X0);
01261     Particles[Particles.Size()-1]->I          = 1.0, 1.0, 1.0;
01262     Particles[Particles.Size()-1]->x          = 0.5*(X0 + X1);
01263     Particles[Particles.Size()-1]->Ekin       = 0.0;
01264     Particles[Particles.Size()-1]->Erot       = 0.0;
01265     Particles[Particles.Size()-1]->Dmax       = sqrt(0.25*dot(X1-X0,X1-X0)+max(R0,R1)*max(R0,R1)) + R;
01266     Particles[Particles.Size()-1]->PropsReady = true;
01267     Particles[Particles.Size()-1]->Index      = Particles.Size()-1;
01268     Particles[Particles.Size()-1]->Tori.Push     (new Torus(&X0,Particles[Particles.Size()-1]->Verts[0],Particles[Particles.Size()-1]->Verts[1]));
01269     Particles[Particles.Size()-1]->Tori.Push     (new Torus(&X1,Particles[Particles.Size()-1]->Verts[3],Particles[Particles.Size()-1]->Verts[4]));
01270     Particles[Particles.Size()-1]->Cylinders.Push(new Cylinder(Particles[Particles.Size()-1]->Tori[0],Particles[Particles.Size()-1]->Tori[1],Particles[Particles.Size()-1]->Verts[2],Particles[Particles.Size()-1]->Verts[5]));
01271 }
01272 
01273 // Methods
01274 
01275 inline void Domain::SetProps (Dict & D)
01276 {
01277     for (size_t i =0 ; i<Particles.Size(); i++)
01278     {
01279         for (size_t j=0; j<D.Keys.Size(); ++j)
01280         {
01281             int tag = D.Keys[j];
01282             if (tag==Particles[i]->Tag)
01283             {
01284                 SDPair const & p = D(tag);
01285                 if (p.HasKey("Gn"))
01286                 {
01287                     Particles[i]->Props.Gn = p("Gn");
01288                 }
01289                 if (p.HasKey("Gt"))
01290                 {
01291                     Particles[i]->Props.Gt = p("Gt");
01292                 }
01293                 if (p.HasKey("Kn"))
01294                 {
01295                     Particles[i]->Props.Kn = p("Kn");
01296                 }
01297                 if (p.HasKey("Kt"))
01298                 {
01299                     Particles[i]->Props.Kt = p("Kt");
01300                 }
01301                 if (p.HasKey("Bn"))
01302                 {
01303                     Particles[i]->Props.Bn = p("Bn");
01304                 }
01305                 if (p.HasKey("Bt"))
01306                 {
01307                     Particles[i]->Props.Bt = p("Bt");
01308                 }
01309                 if (p.HasKey("Bm"))
01310                 {
01311                     Particles[i]->Props.Bm = p("Bm");
01312                 }
01313                 if (p.HasKey("Mu"))
01314                 {
01315                     Particles[i]->Props.Mu = p("Mu");
01316                 }
01317                 if (p.HasKey("Eps"))
01318                 {
01319                     Particles[i]->Props.eps = p("Eps");
01320                 }
01321                 if (p.HasKey("Beta"))
01322                 {
01323                     Particles[i]->Props.Beta = p("Beta");
01324                 }
01325                 if (p.HasKey("Eta"))
01326                 {
01327                     Particles[i]->Props.Eta = p("Eta");
01328                 }
01329             }
01330         }
01331     }
01332     for (size_t i=0; i<BInteractons.Size(); i++)
01333     {
01334         BInteractons[i]->UpdateParameters();
01335     }
01336     for (size_t i=0; i<CInteractons.Size(); i++)
01337     {
01338         CInteractons[i]->UpdateParameters();
01339     }
01340 }
01341 
01342 inline void Domain::Initialize (double dt)
01343 {
01344     if (!Initialized)
01345     {
01346         // initialize all particles
01347         for (size_t i=0; i<Particles.Size(); i++)
01348         {
01349             Particles[i]->Initialize(i);
01350             Particles[i]->InitializeVelocity(dt);
01351         }
01352         //Initializing the energies
01353         Evis = 0.0;
01354         Efric = 0.0;
01355         Wext = 0.0;
01356 
01357         // initialize
01358         ResetInteractons();
01359         // info
01360         Util::Stopwatch stopwatch;
01361         printf("\n%s--- Initializing particles ------------------------------------------------------%s\n",TERM_CLR1,TERM_RST);
01362         // set flag
01363         Initialized = true;
01364 
01365         // info
01366         double Ekin, Epot, Etot;
01367         Etot = CalcEnergy (Ekin, Epot);
01368         printf("%s  Kinematic energy   = %g%s\n",TERM_CLR4, Ekin, TERM_RST);
01369         printf("%s  Potential energy   = %g%s\n",TERM_CLR4, Epot, TERM_RST);
01370         printf("%s  Total energy       = %g%s\n",TERM_CLR2, Etot, TERM_RST);
01371     }
01372     else
01373     {
01374         for (size_t i=0; i<Particles.Size(); i++)
01375         {
01376             if (Particles[i]->vxf) Particles[i]->xb(0) = Particles[i]->x(0) - Particles[i]->v(0)*dt;
01377             if (Particles[i]->vyf) Particles[i]->xb(1) = Particles[i]->x(1) - Particles[i]->v(1)*dt;
01378             if (Particles[i]->vzf) Particles[i]->xb(2) = Particles[i]->x(2) - Particles[i]->v(2)*dt;
01379         }
01380     }
01381 
01382 }
01383 
01384 inline void Domain::Solve (double tf, double dt, double dtOut, ptFun_t ptSetup, ptFun_t ptReport, char const * TheFileKey, bool RenderVideo, size_t Nproc)
01385 {
01386     // Assigning some domain particles especifically to the output
01387     FileKey.Printf("%s",TheFileKey);
01388     idx_out = 0;
01389 
01390     // initialize particles
01391     Initialize (dt);
01392 
01393     // set the displacement of the particles to zero (for the Halo)
01394     ResetDisplacements();
01395 
01396     // build the map of possible contacts (for the Halo)
01397     ResetContacts();
01398 
01399     // calc the total volume of particles (solids)
01400     Vs = 0.0;
01401     Ms = 0.0;
01402     for (size_t i=0; i<Particles.Size(); i++) 
01403     { 
01404         if (Particles[i]->IsFree())
01405         {
01406             Vs += Particles[i]->Props.V;
01407             Ms += Particles[i]->Props.m;
01408         }
01409     }
01410 
01411     // info
01412     Util::Stopwatch stopwatch;
01413     printf("\n%s--- Solving ---------------------------------------------------------------------%s\n",TERM_CLR1,TERM_RST);
01414 
01415     // solve
01416     double t0   = Time;     // initial time
01417     double tout = t0+dtOut; // time position for output
01418 
01419     // report
01420     Finished = false;
01421     if (ptReport!=NULL) (*ptReport) ((*this), UserData);
01422 
01423     // string to output energy data, if user gives the FileKey
01424     std::ostringstream oss_energy; 
01425     EnergyOutput (idx_out, oss_energy);
01426 
01427     // run
01428     while (Time<tf)
01429     {
01430 
01431         // initialize forces and torques
01432         for (size_t i=0; i<Particles.Size(); i++)
01433         {
01434             // set the force and torque to the fixed values
01435             Particles[i]->F = Particles[i]->Ff;
01436             Particles[i]->T = Particles[i]->Tf;
01437             for (size_t n=0;n<3;n++)
01438             {
01439                 for (size_t m=0;m<3;m++)  
01440                 {
01441                     Particles[i]->M(n,m)=0.0;
01442                     Particles[i]->B(n,m)=0.0;
01443                 }
01444             }
01445 
01446             // initialize the coordination (number of contacts per particle) number
01447             Particles[i]->Cn = 0.0;
01448 
01449             // external work added to the system by the fixed forces Ff
01450             Wext += dot(Particles[i]->Ff,Particles[i]->v)*dt;
01451         }
01452 
01453         // calc contact forces: collision and bonding (cohesion)
01454 #ifdef USE_THREAD
01455         // declare a thread array for the interactons
01456         vector<std::thread> IT;
01457         for (size_t n=0;n<Nproc;n++)
01458         {
01459             IT.push_back(std::thread(std::bind(GlobalForce,&Interactons,dt,n,Nproc)));
01460         }
01461         for (size_t n=0;n<Nproc;n++)
01462         {
01463             IT[n].join();
01464         }
01465 #else
01466         for (size_t i=0; i<Interactons.Size(); i++)
01467         {
01468             Interactons[i]->CalcForce (dt);
01469         }
01470 #endif
01471 
01472         // calculate the collision energy
01473         for (size_t i=0; i<CInteractons.Size(); i++)
01474         {
01475             Evis  += CInteractons[i]-> dEvis;
01476             Efric += CInteractons[i]-> dEfric;
01477         }
01478 
01479         // tell the user function to update its data
01480         if (ptSetup!=NULL) (*ptSetup) ((*this), UserData);
01481 
01482 
01483         // move particles
01484 #ifdef USE_THREAD
01485         // declare a thread array for the particles
01486         vector<std::thread> MT;
01487         Array<double>   TMD;
01488         TMD.Resize(Nproc);
01489         for (size_t n=0;n<Nproc;n++)
01490         {
01491              //call the function move for each thread
01492             MT.push_back(std::thread(std::bind(GlobalMove,&Particles,dt,TMD[n],n,Nproc)));
01493         }
01494         for (size_t n=0;n<Nproc;n++)
01495         {
01496             // wait for all the threads to finish
01497             MT[n].join();
01498         }
01499 #else 
01500         for (size_t i=0; i<Particles.Size(); i++)
01501         {
01502             Particles[i]->Translate (dt);
01503             Particles[i]->Rotate    (dt);
01504         }
01505 #endif
01506 
01507         // output
01508         if (Time>=tout)
01509         {
01510             idx_out++;
01511             if (BInteractons.Size()>0) Clusters();
01512             if (ptReport!=NULL) (*ptReport) ((*this), UserData);
01513             if (TheFileKey!=NULL)
01514             {
01515                 String fn;
01516                 fn.Printf    ("%s_%04d", TheFileKey, idx_out);
01517                 if(RenderVideo) WritePOV     (fn.CStr());
01518                 EnergyOutput (idx_out, oss_energy);
01519             }
01520             tout += dtOut;
01521         }
01522 
01523 
01524         // next time position
01525         Time += dt;
01526 
01527 
01528 #ifdef USE_THREAD
01529         double maxdis = TMD.TheMax();
01530         //std::cout << TMD.TheMax() << std::endl;
01531         maxdis = MaxDisplacement();
01532 #else 
01533         double maxdis = MaxDisplacement();
01534 #endif
01535         // update the Halos
01536         if (maxdis>Alpha)
01537         {
01538             ResetDisplacements();
01539             ResetContacts();
01540         }
01541 
01542         //if (fabs(Time-7.15013)<1.0e-5) WriteBPY("test");
01543     }
01544 
01545     // last output
01546     Finished = true;
01547     if (ptReport!=NULL) (*ptReport) ((*this), UserData);
01548 
01549     // save energy data
01550     if (TheFileKey!=NULL)
01551     {
01552         String fn;
01553         fn.Printf("%s_energy.res",TheFileKey);
01554         std::ofstream fe(fn.CStr());
01555         fe << oss_energy.str();
01556         fe.close();
01557     }
01558 
01559     // info
01560     double Ekin, Epot, Etot;
01561     Etot = CalcEnergy (Ekin, Epot);
01562     printf("%s  Kinematic energy   = %g%s\n",TERM_CLR4, Ekin, TERM_RST);
01563     printf("%s  Potential energy   = %g%s\n",TERM_CLR4, Epot, TERM_RST);
01564     printf("%s  Total energy       = %g%s\n",TERM_CLR2, Etot, TERM_RST);
01565 }
01566 
01567 inline void Domain::WritePOV (char const * FileKey)
01568 {
01569     String fn(FileKey);
01570     fn.append(".pov");
01571     std::ofstream of(fn.CStr(), std::ios::out);
01572     POVHeader (of);
01573     POVSetCam (of, CamPos, OrthoSys::O);
01574     Array <String> Colors(10);
01575     Colors = "Gray","Blue","Yellow","Gold","Green","Blue","Orange","Salmon","Copper","Aquamarine";
01576     for (size_t i=0; i<Particles.Size(); i++)
01577     {
01578         if (!Particles[i]->IsFree()) Particles[i]->Draw(of,"Col_Glass_Bluish");
01579         else
01580         {
01581             bool found = false;
01582             for (size_t j=0;j<Listofclusters.Size();j++)
01583             {
01584                 if (Listofclusters[j].Has(i)&&BInteractons.Size()>0)
01585                 {
01586                     Particles[i]->Draw(of,Colors[j%10].CStr());
01587                     found = true;
01588                     break;
01589                 }
01590             }
01591             if (!found) Particles[i]->Draw(of,"Red");
01592         }
01593     }
01594 
01595 }
01596 
01597 inline void Domain::WriteBPY (char const * FileKey)
01598 {
01599     String fn(FileKey);
01600     fn.append(".bpy");
01601     std::ofstream of(fn.CStr(), std::ios::out);
01602     BPYHeader(of);
01603     for (size_t i=0; i<Particles.Size(); i++) Particles[i]->Draw (of,"",true);
01604     of.close();
01605 }
01606 
01607 #ifdef USE_HDF5
01608 inline void Domain::Save (char const * FileKey)
01609 {
01610 
01611     // Opening the file for writing
01612     String fn(FileKey);
01613     fn.append(".hdf5");
01614     hid_t file_id;
01615     file_id = H5Fcreate(fn.CStr(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
01616 
01617     // Storing the number of particles in the domain
01618     int data[1];
01619     data[0]=Particles.Size();
01620     hsize_t dims[1];
01621     dims[0]=1;
01622     H5LTmake_dataset_int(file_id,"/NP",1,dims,data);
01623 
01624     for (size_t i=0; i<Particles.Size(); i++)
01625     {
01626         // Creating the string and the group for each particle
01627         hid_t group_id;
01628         String par;
01629         par.Printf("/Particle_%08d",i);
01630         group_id = H5Gcreate(file_id, par.CStr(), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
01631 
01632 
01633         // Storing some scalar variables
01634         double dat[1];
01635         dat[0] = Particles[i]->Props.R;
01636         H5LTmake_dataset_double(group_id,"SR",1,dims,dat);
01637         dat[0] = Particles[i]->Props.rho;
01638         H5LTmake_dataset_double(group_id,"Rho",1,dims,dat);
01639         dat[0] = Particles[i]->Props.m;
01640         H5LTmake_dataset_double(group_id,"m",1,dims,dat);
01641         dat[0] = Particles[i]->Props.V;
01642         H5LTmake_dataset_double(group_id,"V",1,dims,dat);
01643         dat[0] = Particles[i]->Diam;
01644         H5LTmake_dataset_double(group_id,"Diam",1,dims,dat);
01645         dat[0] = Particles[i]->Dmax;
01646         H5LTmake_dataset_double(group_id,"Dmax",1,dims,dat);
01647         int datint[1];
01648         datint[0] = Particles[i]->Index;
01649         H5LTmake_dataset_int(group_id,"Index",1,dims,datint);
01650 
01651 
01652         int tag[1];
01653         tag[0] = Particles[i]->Tag;
01654         H5LTmake_dataset_int(group_id,"Tag",1,dims,tag);
01655 
01656         // Storing vectorial variables
01657         double cd[3];
01658         hsize_t dd[1];
01659         dd[0] = 3;
01660 
01661         cd[0]=Particles[i]->x(0);
01662         cd[1]=Particles[i]->x(1);
01663         cd[2]=Particles[i]->x(2);
01664         H5LTmake_dataset_double(group_id,"x",1,dd,cd);
01665 
01666         cd[0]=Particles[i]->xb(0);
01667         cd[1]=Particles[i]->xb(1);
01668         cd[2]=Particles[i]->xb(2);
01669         H5LTmake_dataset_double(group_id,"xb",1,dd,cd);
01670 
01671         cd[0]=Particles[i]->v(0);
01672         cd[1]=Particles[i]->v(1);
01673         cd[2]=Particles[i]->v(2);
01674         H5LTmake_dataset_double(group_id,"v",1,dd,cd);
01675 
01676         cd[0]=Particles[i]->w(0);
01677         cd[1]=Particles[i]->w(1);
01678         cd[2]=Particles[i]->w(2);
01679         H5LTmake_dataset_double(group_id,"w",1,dd,cd);
01680 
01681         cd[0]=Particles[i]->wb(0);
01682         cd[1]=Particles[i]->wb(1);
01683         cd[2]=Particles[i]->wb(2);
01684         H5LTmake_dataset_double(group_id,"wb",1,dd,cd);
01685 
01686         cd[0]=Particles[i]->I(0);
01687         cd[1]=Particles[i]->I(1);
01688         cd[2]=Particles[i]->I(2);
01689         H5LTmake_dataset_double(group_id,"I",1,dd,cd);
01690 
01691         double cq[4];
01692         dd[0] = 4;
01693         cq[0]=Particles[i]->Q(0);
01694         cq[1]=Particles[i]->Q(1);
01695         cq[2]=Particles[i]->Q(2);
01696         cq[3]=Particles[i]->Q(3);
01697         H5LTmake_dataset_double(group_id,"Q",1,dd,cq);
01698 
01699 
01700 
01701 
01702         // Storing the number of vertices of each particle
01703         data[0] = Particles[i]->Verts.Size();
01704         H5LTmake_dataset_int(group_id,"n_vertices",1,dims,data);
01705         hid_t gv_id;
01706         gv_id = H5Gcreate(group_id,"Verts", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
01707 
01708         // Storing each vertex 
01709         for (size_t j=0;j<Particles[i]->Verts.Size();j++)
01710         {
01711             String parv;
01712             parv.Printf("Verts_%08d",j);
01713             double cod[3];
01714             cod[0]=(*Particles[i]->Verts[j])(0);
01715             cod[1]=(*Particles[i]->Verts[j])(1);
01716             cod[2]=(*Particles[i]->Verts[j])(2);
01717             hsize_t dim[1];
01718             dim[0]=3;
01719             H5LTmake_dataset_double(gv_id,parv.CStr(),1,dim,cod);
01720         }
01721 
01722         // Number of edges of the particle
01723         data[0] = Particles[i]->Edges.Size();
01724         H5LTmake_dataset_int(group_id,"n_edges",1,dims,data);
01725         gv_id = H5Gcreate(group_id,"Edges", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
01726 
01727         // Edges
01728         for (size_t j=0;j<Particles[i]->Edges.Size();j++)
01729         {
01730             String parv;
01731             parv.Printf("Edges_%08d",j);
01732             int co[2];
01733             co[0] = Particles[i]->EdgeCon[j][0];
01734             co[1] = Particles[i]->EdgeCon[j][1];
01735             hsize_t dim[1];
01736             dim[0] =2;
01737             H5LTmake_dataset_int(gv_id,parv.CStr(),1,dim,co);
01738         }
01739         
01740         // Number of faces of the particle
01741         data[0] = Particles[i]->Faces.Size();
01742         H5LTmake_dataset_int(group_id,"n_faces",1,dims,data);
01743         gv_id = H5Gcreate(group_id,"Faces", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
01744         
01745         // Faces
01746         for (size_t j=0;j<Particles[i]->Faces.Size();j++)
01747         {
01748             String parv;
01749             parv.Printf("Faces_%08d",j);
01750             int co[Particles[i]->FaceCon[j].Size()];
01751             hsize_t dim[1];
01752             dim[0]= Particles[i]->FaceCon[j].Size();
01753             for (size_t k=0;k<Particles[i]->FaceCon[j].Size();k++)
01754             {
01755                 co[k]=Particles[i]->FaceCon[j][k];
01756             }
01757             H5LTmake_dataset_int(gv_id,parv.CStr(),1,dim,co);
01758         }
01759         
01760     }
01761    
01762     H5Fclose(file_id);
01763 
01764 
01765 }
01766 
01767 inline void Domain::Load (char const * FileKey)
01768 {
01769 
01770     // Opening the file for reading
01771     String fn(FileKey);
01772     fn.append(".hdf5");
01773     hid_t file_id;
01774     file_id = H5Fopen(fn.CStr(), H5F_ACC_RDONLY, H5P_DEFAULT);
01775 
01776     // Number of particles in the domain
01777     int data[1];
01778     H5LTread_dataset_int(file_id,"/NP",data);
01779     size_t NP = data[0];
01780 
01781     // Loading the particles
01782     for (size_t i=0; i<NP; i++)
01783     {
01784 
01785         // Creating the string and the group for each particle
01786         hid_t group_id;
01787         String par;
01788         par.Printf("/Particle_%08d",i);
01789         group_id = H5Gopen(file_id, par.CStr(),H5P_DEFAULT);
01790 
01791         // Finding the particle's position for the domain decomposition
01792         double X[3];
01793         H5LTread_dataset_double(group_id,"x",X);
01794 
01795 
01796         // Loading the Vertices
01797         H5LTread_dataset_int(group_id,"n_vertices",data);
01798         size_t nv = data[0];
01799         hid_t gv_id;
01800         gv_id = H5Gopen(group_id,"Verts", H5P_DEFAULT);
01801         Array<Vec3_t> V;
01802 
01803         for (size_t j=0;j<nv;j++)
01804         {
01805             String parv;
01806             parv.Printf("Verts_%08d",j);
01807             double cod[3];
01808             H5LTread_dataset_double(gv_id,parv.CStr(),cod);
01809             V.Push(Vec3_t(cod[0],cod[1],cod[2]));
01810         }
01811         
01812         // Loading the edges
01813         H5LTread_dataset_int(group_id,"n_edges",data);
01814         size_t ne = data[0];
01815         gv_id = H5Gopen(group_id,"Edges", H5P_DEFAULT);
01816         Array<Array <int> > E;
01817 
01818         for (size_t j=0;j<ne;j++)
01819         {
01820             String parv;
01821             parv.Printf("Edges_%08d",j);
01822             int cod[2];
01823             H5LTread_dataset_int(gv_id,parv.CStr(),cod);
01824             Array<int> Ep(2);
01825             Ep[0]=cod[0];
01826             Ep[1]=cod[1];
01827             E.Push(Ep);
01828         }
01829 
01830         // Loading the faces
01831 
01832         // Number of faces of the particle
01833         H5LTread_dataset_int(group_id,"n_faces",data);
01834         size_t nf = data[0];
01835         gv_id = H5Gopen(group_id,"Faces", H5P_DEFAULT);
01836         Array<Array <int> > F;
01837         
01838         // Faces
01839         for (size_t j=0;j<nf;j++)
01840         {
01841             String parv;
01842             parv.Printf("Faces_%08d",j);
01843             hsize_t dim[1];
01844             H5LTget_dataset_info(gv_id,parv.CStr(),dim,NULL,NULL);
01845             size_t ns = (size_t)dim[0];
01846             int co[ns];
01847             Array<int> Fp(ns);
01848 
01849             H5LTread_dataset_int(gv_id,parv.CStr(),co);
01850             
01851             for (size_t k=0;k<ns;k++)
01852             {
01853                 Fp[k] = co[k];
01854             }
01855 
01856             F.Push(Fp);
01857 
01858         }
01859 
01860         Particles.Push (new Particle(-1,V,E,F,OrthoSys::O,OrthoSys::O,0.1,1.0));
01861 
01862         // Loading vectorial variables
01863         Particles[Particles.Size()-1]->x = Vec3_t(X[0],X[1],X[2]);
01864         double cd[3];
01865         H5LTread_dataset_double(group_id,"xb",cd);
01866         Particles[Particles.Size()-1]->xb = Vec3_t(cd[0],cd[1],cd[2]);
01867         H5LTread_dataset_double(group_id,"v",cd);
01868         Particles[Particles.Size()-1]->v = Vec3_t(cd[0],cd[1],cd[2]);
01869         H5LTread_dataset_double(group_id,"w",cd);
01870         Particles[Particles.Size()-1]->w = Vec3_t(cd[0],cd[1],cd[2]);
01871         H5LTread_dataset_double(group_id,"wb",cd);
01872         Particles[Particles.Size()-1]->wb = Vec3_t(cd[0],cd[1],cd[2]);
01873         H5LTread_dataset_double(group_id,"I",cd);
01874         Particles[Particles.Size()-1]->I = Vec3_t(cd[0],cd[1],cd[2]);
01875 
01876         double cq[4];
01877         H5LTread_dataset_double(group_id,"Q",cq);
01878         Particles[Particles.Size()-1]->Q = Quaternion_t(cq[0],cq[1],cq[2],cq[3]);
01879 
01880         // Loading the scalar quantities of the particle
01881         double dat[1];
01882         H5LTread_dataset_double(group_id,"SR",dat);
01883         Particles[Particles.Size()-1]->Props.R = dat[0];
01884         H5LTread_dataset_double(group_id,"Rho",dat);
01885         Particles[Particles.Size()-1]->Props.rho = dat[0];
01886         H5LTread_dataset_double(group_id,"m",dat);
01887         Particles[Particles.Size()-1]->Props.m = dat[0];
01888         H5LTread_dataset_double(group_id,"V",dat);
01889         Particles[Particles.Size()-1]->Props.V = dat[0];
01890         H5LTread_dataset_double(group_id,"Diam",dat);
01891         Particles[Particles.Size()-1]->Diam = dat[0];
01892         H5LTread_dataset_double(group_id,"Dmax",dat);
01893         Particles[Particles.Size()-1]->Dmax = dat[0];
01894         int datint[1];
01895         H5LTread_dataset_int(group_id,"Index",datint);
01896         Particles[Particles.Size()-1]->Index = datint[0];
01897         int tag[1];
01898         H5LTread_dataset_int(group_id,"Tag",tag);
01899         Particles[Particles.Size()-1]->Tag = tag[0];
01900         Particles[Particles.Size()-1]->PropsReady = true;
01901 
01902     }
01903 
01904 
01905     H5Fclose(file_id);
01906 
01907 }
01908 #endif
01909 
01910 inline void Domain::BoundingBox(Vec3_t & minX, Vec3_t & maxX)
01911 {
01912     minX = Vec3_t(Particles[0]->MinX(), Particles[0]->MinY(), Particles[0]->MinZ());
01913     maxX = Vec3_t(Particles[0]->MaxX(), Particles[0]->MaxY(), Particles[0]->MaxZ());
01914     for (size_t i=1; i<Particles.Size(); i++)
01915     {
01916         if (minX(0)>Particles[i]->MinX()&&Particles[i]->IsFree()) minX(0) = Particles[i]->MinX();
01917         if (minX(1)>Particles[i]->MinY()&&Particles[i]->IsFree()) minX(1) = Particles[i]->MinY();
01918         if (minX(2)>Particles[i]->MinZ()&&Particles[i]->IsFree()) minX(2) = Particles[i]->MinZ();
01919         if (maxX(0)<Particles[i]->MaxX()&&Particles[i]->IsFree()) maxX(0) = Particles[i]->MaxX();
01920         if (maxX(1)<Particles[i]->MaxY()&&Particles[i]->IsFree()) maxX(1) = Particles[i]->MaxY();
01921         if (maxX(2)<Particles[i]->MaxZ()&&Particles[i]->IsFree()) maxX(2) = Particles[i]->MaxZ();
01922     }
01923 }
01924 
01925 inline void Domain::Center(Vec3_t C)
01926 {
01927     Vec3_t minX,maxX;
01928     BoundingBox(minX,maxX);
01929     Vec3_t Transport(-0.5*(maxX+minX));
01930     Transport += C;
01931     for (size_t i=0; i<Particles.Size(); i++) Particles[i]->Translate(Transport);
01932 }
01933 
01934 inline void Domain::ResetInteractons()
01935 {
01936     // delete old interactors
01937     for (size_t i=0; i<CInteractons.Size(); ++i)
01938     {
01939         if (CInteractons[i]!=NULL) delete CInteractons[i];
01940     }
01941 
01942     // new interactors
01943     CInteractons.Resize(0);
01944     for (size_t i=0; i<Particles.Size()-1; i++)
01945     {
01946         bool pi_has_vf = !Particles[i]->IsFree();
01947         for (size_t j=i+1; j<Particles.Size(); j++)
01948         {
01949             bool pj_has_vf = !Particles[j]->IsFree();
01950 
01951 
01952             // if both particles have any component specified or they are far away, don't create any intereactor
01953             bool close = (Distance(Particles[i]->x,Particles[j]->x)<=Particles[i]->Dmax+Particles[j]->Dmax+2*Alpha);
01954             if ((pi_has_vf && pj_has_vf) || !close ) continue;
01955             Listofpairs.insert(make_pair(Particles[i],Particles[j]));
01956 
01957             // if both particles are spheres (just one vertex)
01958             if (Particles[i]->Verts.Size()==1 && Particles[j]->Verts.Size()==1)
01959             {
01960                 CInteractons.Push (new CInteractonSphere(Particles[i],Particles[j]));
01961             }
01962 
01963             // normal particles
01964             else
01965             {
01966                 CInteractons.Push (new CInteracton(Particles[i],Particles[j]));
01967             }
01968         }
01969     }
01970 }
01971 
01972 inline void Domain::ResetDisplacements()
01973 {
01974     for (size_t i=0; i<Particles.Size(); i++)
01975     {
01976         Particles[i]->ResetDisplacements();
01977     }
01978 }
01979 
01980 inline double Domain::MaxDisplacement()
01981 {
01982     double md = 0.0;
01983     for (size_t i=0; i<Particles.Size(); i++)
01984     {
01985         double mpd = Particles[i]->MaxDisplacement();
01986         if (mpd > md) md = mpd;
01987     }
01988     return md;
01989 }
01990 
01991 inline void Domain::ResetContacts()
01992 {
01993     for (size_t i=0; i<Particles.Size()-1; i++)
01994     {
01995         bool pi_has_vf = !Particles[i]->IsFree();
01996         for (size_t j=i+1; j<Particles.Size(); j++)
01997         {
01998             bool pj_has_vf = !Particles[j]->IsFree();
01999 
02000             bool close = (Distance(Particles[i]->x,Particles[j]->x)<=Particles[i]->Dmax+Particles[j]->Dmax+2*Alpha);
02001             if ((pi_has_vf && pj_has_vf) || !close) continue;
02002             
02003             // checking if the interacton exist for that pair of particles
02004             set<pair<Particle *, Particle *> >::iterator it = Listofpairs.find(make_pair(Particles[i],Particles[j]));
02005             if (it != Listofpairs.end())
02006             {
02007                 continue;
02008             }
02009             Listofpairs.insert(make_pair(Particles[i],Particles[j]));
02010             
02011             // if both particles are spheres (just one vertex)
02012             if (Particles[i]->Verts.Size()==1 && Particles[j]->Verts.Size()==1)
02013             {
02014                 CInteractons.Push (new CInteractonSphere(Particles[i],Particles[j]));
02015             }
02016 
02017             // normal particles
02018             else
02019             {
02020                 CInteractons.Push (new CInteracton(Particles[i],Particles[j]));
02021             }
02022         }
02023     }
02024 
02025     Interactons.Resize(0);
02026     for (size_t i=0; i<CInteractons.Size(); i++)
02027     {
02028         if(CInteractons[i]->UpdateContacts(Alpha)) Interactons.Push(CInteractons[i]);
02029     }
02030     for (size_t i=0; i<BInteractons.Size(); i++)
02031     {
02032         if(BInteractons[i]->UpdateContacts(Alpha)) Interactons.Push(BInteractons[i]);
02033     }
02034 }
02035 
02036 // Auxiliar methods
02037 
02038 inline void Domain::LinearMomentum (Vec3_t & L)
02039 {
02040     L = 0.,0.,0.;
02041     for (size_t i=0; i<Particles.Size(); i++)
02042     {
02043         L += Particles[i]->Props.m*Particles[i]->v;
02044     }
02045 }
02046 
02047 inline void Domain::AngularMomentum (Vec3_t & L)
02048 {
02049     L = 0.,0.,0.;
02050     for (size_t i=0; i<Particles.Size(); i++)
02051     {
02052         Vec3_t t1,t2;
02053         t1 = Particles[i]->I(0)*Particles[i]->w(0),Particles[i]->I(1)*Particles[i]->w(1),Particles[i]->I(2)*Particles[i]->w(2);
02054         Rotation (t1,Particles[i]->Q,t2);
02055         L += Particles[i]->Props.m*cross(Particles[i]->x,Particles[i]->v)+t2;
02056     }
02057 }
02058 
02059 inline double Domain::CalcEnergy (double & Ekin, double & Epot)
02060 {
02061     // kinematic energy
02062     Ekin = 0.0;
02063     for (size_t i=0; i<Particles.Size(); i++)
02064     {
02065         Ekin += Particles[i]->Ekin + Particles[i]->Erot;
02066     }
02067 
02068     // potential energy
02069     Epot = 0.0;
02070     for (size_t i=0; i<CInteractons.Size(); i++)
02071     {
02072         Epot += CInteractons[i]->Epot;
02073     }
02074 
02075     // total energy
02076     return Ekin + Epot;
02077 }
02078 
02079 inline void Domain::EnergyOutput (size_t IdxOut, std::ostream & OF)
02080 {
02081     // header
02082     if (IdxOut==0)
02083     {
02084         OF << Util::_10_6 << "Time" << Util::_8s << "Ekin" << Util::_8s << "Epot" << Util::_8s << "Evis" << Util::_8s << "Efric" << Util::_8s << "Wext" << std::endl;
02085     }
02086     double Ekin,Epot;
02087     CalcEnergy(Ekin,Epot);
02088     OF << Util::_10_6 << Time << Util::_8s << Ekin << Util::_8s << Epot << Util::_8s << Evis << Util::_8s << Efric << Util::_8s << Wext << std::endl;
02089 }
02090 
02091 inline void Domain::GetGSD (Array<double> & X, Array<double> & Y, Array<double> & D, size_t NDiv) const
02092 {
02093     // calc GSD information
02094     Array<double> Vg;
02095     double Vs = 0.0;
02096 
02097     for (size_t i=0; i<Particles.Size(); i++)
02098     {
02099         Particle * P = Particles[i];
02100         double Diam = sqrt((P->MaxX()-P->MinX())*(P->MaxX()-P->MinX())+(P->MaxY()-P->MinY())*(P->MaxY()-P->MinY())+(P->MaxZ()-P->MinZ())*(P->MaxX()-P->MinX()));
02101         Vs += Particles[i]->Props.V;
02102         Vg.Push(Particles[i]->Props.V);
02103         D.Push(Diam);
02104     }
02105     double Dmin  = D[D.TheMin()]; // minimum diameter
02106     double Dmax  = D[D.TheMax()]; // maximum diameter
02107     double Dspan = (Dmax-Dmin)/NDiv;
02108     for (size_t i=0; i<=NDiv; i++)
02109     {
02110         X.Push (i*Dspan+Dmin);
02111         double cumsum = 0;
02112         for (size_t j=0; j<D.Size(); j++)
02113         {
02114             if (D[j]<=i*Dspan+Dmin) cumsum++;
02115         }
02116         Y.Push (cumsum/Particles.Size());
02117     }
02118 }
02119 
02120 inline void Domain::Clusters ()
02121 {
02122     Array<int> connections;
02123     for (size_t i=0;i<BInteractons.Size();i++)
02124     {
02125         if (BInteractons[i]->valid)
02126         {
02127             connections.Push(BInteractons[i]->P1->Index);
02128             connections.Push(BInteractons[i]->P2->Index);
02129         }
02130     }
02131 
02132     Util::Tree tree(connections);
02133     tree.GetClusters(Listofclusters);
02134 }
02135 
02136 inline void Domain::DelParticles (Array<int> const & Tags)
02137 {
02138     Array<int> idxs; // indices to be deleted
02139     for (size_t i=0; i<Particles.Size(); ++i)
02140     {
02141         for (size_t j=0; j<Tags.Size(); ++j)
02142         {
02143             if (Particles[i]->Tag==Tags[j]) idxs.Push(i);
02144         }
02145     }
02146     if (idxs.Size()<1) throw new Fatal("Domain::DelParticles: Could not find any particle to be deleted");
02147     Particles.DelItems (idxs);
02148 }
02149 
02150 inline Particle * Domain::GetParticle (int Tag, bool Check)
02151 {
02152     size_t idx   = 0;
02153     size_t count = 0;
02154     for (size_t i=0; i<Particles.Size(); ++i)
02155     {
02156         if (Particles[i]->Tag==Tag)
02157         {
02158             if (!Check) return Particles[i];
02159             idx = i;
02160             count++;
02161         }
02162     }
02163     if      (count==0) throw new Fatal("Domain::GetParticle: Could not find Particle with Tag==%d",Tag);
02164     else if (count>1)  throw new Fatal("Domain::GetParticle: There are more than one particle with Tag==%d",Tag);
02165     return Particles[idx];
02166 }
02167 
02168 inline Particle const & Domain::GetParticle (int Tag, bool Check) const
02169 {
02170     size_t idx   = 0;
02171     size_t count = 0;
02172     for (size_t i=0; i<Particles.Size(); ++i)
02173     {
02174         if (Particles[i]->Tag==Tag)
02175         {
02176             if (!Check) return (*Particles[i]);
02177             idx = i;
02178             count++;
02179         }
02180     }
02181     if      (count==0) throw new Fatal("Domain::GetParticle: Could not find Particle with Tag==%d",Tag);
02182     else if (count>1)  throw new Fatal("Domain::GetParticle: There are more than one particle with Tag==%d",Tag);
02183     return (*Particles[idx]);
02184 }
02185 
02186 inline void Domain::GetParticles (int Tag, Array<Particle*> & P)
02187 {
02188     P.Resize(0);
02189     for (size_t i=0; i<Particles.Size(); ++i)
02190     {
02191         if (Particles[i]->Tag==Tag) P.Push(Particles[i]);
02192     }
02193     if (P.Size()==0) throw new Fatal("Domain::GetParticles: Could not find any Particle with Tag==%d",Tag);
02194 }
02195 
02196 }; // namespace DEM
02197 
02198 #endif // MECHSYS_DEM_DOMAIN_H
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines