~ubuntu-branches/ubuntu/trusty/yade/trusty

« back to all changes in this revision

Viewing changes to pkg/dem/Polyhedra.cpp

  • Committer: Package Import Robot
  • Author(s): Anton Gladky, cf3f8d9
  • Date: 2013-10-30 20:56:33 UTC
  • mfrom: (20.1.9 sid)
  • Revision ID: package-import@ubuntu.com-20131030205633-1f01r7hjce17d723
Tags: 1.05.0-2
[cf3f8d9] Pass -ftrack-macro-expansion=0 only if gcc>=4.8. (Closes: #726009)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// © 2013 Jan Elias, http://www.fce.vutbr.cz/STM/elias.j/, elias.j@fce.vutbr.cz
 
2
// https://www.vutbr.cz/www_base/gigadisk.php?i=95194aa9a
 
3
 
 
4
#ifdef YADE_CGAL
 
5
 
 
6
#include<yade/core/Interaction.hpp>
 
7
#include<yade/core/Omega.hpp>
 
8
#include<yade/core/Scene.hpp>
 
9
#include<yade/core/State.hpp>
 
10
#include<yade/pkg/common/ElastMat.hpp>
 
11
#include<yade/pkg/common/Aabb.hpp>
 
12
#include"Polyhedra.hpp"
 
13
 
 
14
#define _USE_MATH_DEFINES
 
15
 
 
16
YADE_PLUGIN(/* self-contained in hpp: */ (Polyhedra) (PolyhedraGeom) (Bo1_Polyhedra_Aabb) (PolyhedraPhys) (PolyhedraMat) (Ip2_PolyhedraMat_PolyhedraMat_PolyhedraPhys) (PolyhedraVolumetricLaw)
 
17
        /* some code in cpp (this file): */ 
 
18
        #ifdef YADE_OPENGL
 
19
                (Gl1_Polyhedra)
 
20
        #endif  
 
21
        );
 
22
 
 
23
//*********************************************************************************
 
24
/* Polyhedra Constructor */
 
25
 
 
26
void Polyhedra::Initialize(){
 
27
 
 
28
        if (init) return;
 
29
 
 
30
        bool isRandom = false;
 
31
        
 
32
        //get vertices
 
33
        int N = (int) v.size(); 
 
34
        if (N==0) {
 
35
                //generate randomly
 
36
                while ((int) v.size()<4) GenerateRandomGeometry();
 
37
                N = (int) v.size();
 
38
                isRandom = true;
 
39
        }
 
40
 
 
41
        //compute convex hull of vertices       
 
42
        std::vector<CGALpoint> points;
 
43
        points.resize(v.size());
 
44
        for(int i=0;i<N;i++) {
 
45
                points[i] = CGALpoint(v[i][0],v[i][1],v[i][2]);
 
46
        }
 
47
 
 
48
        CGAL::convex_hull_3(points.begin(), points.end(), P);
 
49
        
 
50
        //connect triagular facets if possible
 
51
        std::transform(P.facets_begin(), P.facets_end(), P.planes_begin(),Plane_equation());
 
52
        P = Simplify(P, 1E-9);
 
53
 
 
54
        //modify order of v according to CGAl polyhedron 
 
55
        int i = 0;
 
56
        v.clear();
 
57
        for (Polyhedron::Vertex_iterator vIter = P.vertices_begin(); vIter != P.vertices_end(); ++vIter, i++){
 
58
                v.push_back(Vector3r(vIter->point().x(),vIter->point().y(),vIter->point().z()));
 
59
        }       
 
60
 
 
61
        //list surface triangles for plotting
 
62
        faceTri.clear();
 
63
        std::transform(P.facets_begin(), P.facets_end(), P.planes_begin(),Plane_equation());
 
64
        for (Polyhedron::Facet_iterator fIter = P.facets_begin(); fIter != P.facets_end(); fIter++){
 
65
                Polyhedron::Halfedge_around_facet_circulator hfc0;
 
66
                int n = fIter->facet_degree();
 
67
                hfc0 = fIter->facet_begin();            
 
68
                int a = std::distance(P.vertices_begin(), hfc0->vertex());
 
69
                for (int i=2; i<n; i++){
 
70
                        ++hfc0;
 
71
                        faceTri.push_back(a);
 
72
                        faceTri.push_back(std::distance(P.vertices_begin(), hfc0->vertex()));
 
73
                        faceTri.push_back(std::distance(P.vertices_begin(), hfc0->next()->vertex()));
 
74
                }
 
75
        }
 
76
 
 
77
        //compute centroid and volume
 
78
        P_volume_centroid(P, &volume, &centroid);
 
79
        //check vierd behavior of CGAL in tessalation
 
80
        if(isRandom && volume*1.75<4./3.*3.14*size[0]/2.*size[1]/2.*size[2]/2.) {
 
81
                v.clear();
 
82
                seed = rand();
 
83
                Initialize();
 
84
        }
 
85
        Vector3r translation((-1)*centroid);
 
86
        
 
87
        //set centroid to be [0,0,0]
 
88
        for(int i=0;i<N;i++) {
 
89
                v[i] = v[i]-centroid;
 
90
        }
 
91
        if(isRandom) centroid = Vector3r::Zero();
 
92
 
 
93
        Vector3r origin(0,0,0);
 
94
 
 
95
        //move and rotate also the CGAL structure Polyhedron
 
96
        Transformation t_trans(1.,0.,0.,translation[0],0.,1.,0.,translation[1],0.,0.,1.,translation[2],1.);             
 
97
        std::transform( P.points_begin(), P.points_end(), P.points_begin(), t_trans);   
 
98
 
 
99
        //compute inertia       
 
100
        double vtet;
 
101
        Vector3r ctet;
 
102
        Matrix3r Itet1, Itet2;
 
103
        Matrix3r inertia_tensor(Matrix3r::Zero());
 
104
        for(int i=0; i<(int) faceTri.size(); i+=3){
 
105
                vtet = std::abs((origin-v[faceTri[i+2]]).dot((v[faceTri[i]]-v[faceTri[i+2]]).cross(v[faceTri[i+1]]-v[faceTri[i+2]]))/6.);               
 
106
                ctet = (origin+v[faceTri[i]]+v[faceTri[i+1]]+v[faceTri[i+2]]) / 4.;
 
107
                Itet1 = TetraInertiaTensor(origin-ctet, v[faceTri[i]]-ctet, v[faceTri[i+1]]-ctet, v[faceTri[i+2]]-ctet);
 
108
                ctet = ctet-origin;
 
109
                Itet2<<
 
110
                        ctet[1]*ctet[1]+ctet[2]*ctet[2], -ctet[0]*ctet[1], -ctet[0]*ctet[2],
 
111
                        -ctet[0]*ctet[1], ctet[0]*ctet[0]+ctet[2]*ctet[2], -ctet[2]*ctet[1],
 
112
                        -ctet[0]*ctet[2], -ctet[2]*ctet[1], ctet[1]*ctet[1]+ctet[0]*ctet[0];
 
113
                inertia_tensor = inertia_tensor + Itet1 + Itet2*vtet; 
 
114
        }       
 
115
 
 
116
        if(abs(inertia_tensor(0,1))+abs(inertia_tensor(0,2))+abs(inertia_tensor(1,2)) < 1E-13){
 
117
                // no need to rotate, inertia already diagonal
 
118
                orientation = Quaternionr::Identity();
 
119
                inertia = Vector3r(inertia_tensor(0,0),inertia_tensor(1,1),inertia_tensor(2,2));
 
120
        }else{
 
121
                // calculate eigenvectors of I
 
122
                Vector3r rot;
 
123
                Matrix3r I_rot(Matrix3r::Zero()), I_new(Matrix3r::Zero()); 
 
124
                matrixEigenDecomposition(inertia_tensor,I_rot,I_new);
 
125
                // I_rot = eigenvectors of inertia_tensors in columns
 
126
                // I_new = eigenvalues on diagonal
 
127
                // set positove direction of vectors - otherwise reloading does not work
 
128
                Matrix3r sign(Matrix3r::Zero()); 
 
129
                double max_v_signed = I_rot(0,0);
 
130
                double max_v = abs(I_rot(0,0));
 
131
                if (max_v < abs(I_rot(1,0))) {max_v_signed = I_rot(1,0); max_v = abs(I_rot(1,0));} 
 
132
                if (max_v < abs(I_rot(2,0))) {max_v_signed = I_rot(2,0); max_v = abs(I_rot(2,0));} 
 
133
                sign(0,0) = max_v_signed/max_v;
 
134
                max_v_signed = I_rot(0,1);
 
135
                max_v = abs(I_rot(0,1));
 
136
                if (max_v < abs(I_rot(1,1))) {max_v_signed = I_rot(1,1); max_v = abs(I_rot(1,1));} 
 
137
                if (max_v < abs(I_rot(2,1))) {max_v_signed = I_rot(2,1); max_v = abs(I_rot(2,1));} 
 
138
                sign(1,1) = max_v_signed/max_v;
 
139
                sign(2,2) = 1.;
 
140
                I_rot = I_rot*sign;
 
141
                // force the eigenvectors to be right-hand oriented
 
142
                Vector3r third = (I_rot.col(0)).cross(I_rot.col(1));
 
143
                I_rot(0,2) = third[0];
 
144
                I_rot(1,2) = third[1];
 
145
                I_rot(2,2) = third[2];  
 
146
                
 
147
                                        
 
148
                inertia = Vector3r(I_new(0,0),I_new(1,1),I_new(2,2));
 
149
                orientation = Quaternionr(I_rot); 
 
150
                //rotate the voronoi cell so that x - is maximal inertia axis and z - is minimal inertia axis
 
151
                //orientation.normalize();  //not needed
 
152
                for(int i=0; i< (int) v.size();i++) {
 
153
                        v[i] =  orientation.conjugate()*v[i];
 
154
                }
 
155
                        
 
156
                //rotate also the CGAL structure Polyhedron
 
157
                Matrix3r rot_mat = (orientation.conjugate()).toRotationMatrix();
 
158
                Transformation t_rot(rot_mat(0,0),rot_mat(0,1),rot_mat(0,2),rot_mat(1,0),rot_mat(1,1),rot_mat(1,2),rot_mat(2,0),rot_mat(2,1),rot_mat(2,2),1.);  
 
159
                std::transform( P.points_begin(), P.points_end(), P.points_begin(), t_rot);
 
160
 
 
161
        }
 
162
        //initialization done
 
163
        init = 1;
 
164
}
 
165
 
 
166
//**************************************************************************
 
167
/* Generator of randomly shaped polyhedron based on Voronoi tessellation*/
 
168
 
 
169
void Polyhedra::GenerateRandomGeometry(){
 
170
        srand(seed);    
 
171
 
 
172
        vector<CGALpoint> nuclei;
 
173
        nuclei.push_back(CGALpoint(5.,5.,5.));
 
174
        CGALpoint trial;
 
175
        int iter = 0; 
 
176
        bool isOK;
 
177
        //fill box 5x5x5 with randomly located nuclei with restricted minimal mutual distance 0.75 which gives approximate mean mutual distance 1;
 
178
        double dist_min2 = 0.75*0.75;
 
179
        while(iter<500){
 
180
                isOK = true;
 
181
                iter++;
 
182
                trial = CGALpoint(double(rand())/RAND_MAX*5.+2.5,double(rand())/RAND_MAX*5.+2.5,double(rand())/RAND_MAX*5.+2.5);
 
183
                for(int i=0;i< (int) nuclei.size();i++) {
 
184
                        isOK = pow(nuclei[i].x()-trial.x(),2)+pow(nuclei[i].y()-trial.y(),2)+pow(nuclei[i].z()-trial.z(),2) > dist_min2;
 
185
                        if (!isOK) break;
 
186
                }
 
187
 
 
188
                if(isOK){
 
189
                        iter = 0;
 
190
                        nuclei.push_back(trial);
 
191
                }                               
 
192
        }       
 
193
        
 
194
        
 
195
        //perform Voronoi tessellation  
 
196
        nuclei.erase(nuclei.begin());
 
197
        Triangulation dt(nuclei.begin(), nuclei.end());
 
198
        Triangulation::Vertex_handle zero_point = dt.insert(CGALpoint(5.,5.,5.));
 
199
        v.clear();
 
200
        std::vector<Triangulation::Cell_handle>  ch_cells;
 
201
        dt.incident_cells(zero_point,std::back_inserter(ch_cells));
 
202
        for(std::vector<Triangulation::Cell_handle>::iterator ci = ch_cells.begin(); ci !=ch_cells.end(); ++ci){
 
203
                v.push_back(FromCGALPoint(dt.dual(*ci))-Vector3r(5.,5.,5.));                            
 
204
        }
 
205
 
 
206
 
 
207
        //resize and rotate the voronoi cell
 
208
        Quaternionr Rot(double(rand())/RAND_MAX,double(rand())/RAND_MAX,double(rand())/RAND_MAX,double(rand())/RAND_MAX);
 
209
        Rot.normalize();
 
210
        for(int i=0; i< (int) v.size();i++) {
 
211
                v[i] = Rot*(Vector3r(v[i][0]*size[0],v[i][1]*size[1],v[i][2]*size[2]));
 
212
        }       
 
213
        
 
214
        //to avoid patological cases (that should not be present, but CGAL works somehow unpredicable)
 
215
        if (v.size() < 8) {
 
216
                cout << "wrong " << v.size() << endl;
 
217
                v.clear();
 
218
                seed = rand();
 
219
                GenerateRandomGeometry();
 
220
        }
 
221
}
 
222
 
 
223
//****************************************************************************************
 
224
/* Destructor */
 
225
 
 
226
Polyhedra::~Polyhedra(){}
 
227
 
 
228
//****************************************************************************************
 
229
/* Destructor */
 
230
 
 
231
PolyhedraGeom::~PolyhedraGeom(){}
 
232
 
 
233
//****************************************************************************************
 
234
/* AaBb overlap checker  */
 
235
 
 
236
void Bo1_Polyhedra_Aabb::go(const shared_ptr<Shape>& ig, shared_ptr<Bound>& bv, const Se3r& se3, const Body*){
 
237
 
 
238
        Polyhedra* t=static_cast<Polyhedra*>(ig.get());
 
239
        if (!t->IsInitialized()) t->Initialize();
 
240
        if(!bv){ bv=shared_ptr<Bound>(new Aabb); }
 
241
        Aabb* aabb=static_cast<Aabb*>(bv.get());
 
242
        //Quaternionr invRot=se3.orientation.conjugate();
 
243
        int N = (int) t->v.size();
 
244
        Vector3r v_g, mincoords(0.,0.,0.), maxcoords(0.,0.,0.);         
 
245
        for(int i=0; i<N; i++) {
 
246
                v_g=se3.orientation*t->v[i]; // vertices in global coordinates
 
247
                mincoords = Vector3r(min(mincoords[0],v_g[0]),min(mincoords[1],v_g[1]),min(mincoords[2],v_g[2]));
 
248
                maxcoords = Vector3r(max(maxcoords[0],v_g[0]),max(maxcoords[1],v_g[1]),max(maxcoords[2],v_g[2]));
 
249
        }
 
250
        aabb->min=se3.position+mincoords;
 
251
        aabb->max=se3.position+maxcoords;
 
252
}
 
253
 
 
254
//**********************************************************************************
 
255
/* Plotting */
 
256
 
 
257
#ifdef YADE_OPENGL
 
258
        #include<yade/lib/opengl/OpenGLWrapper.hpp>
 
259
        void Gl1_Polyhedra::go(const shared_ptr<Shape>& cm, const shared_ptr<State>&,bool,const GLViewInfo&)
 
260
        {
 
261
                glMaterialv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,Vector3r(cm->color[0],cm->color[1],cm->color[2]));
 
262
                glColor3v(cm->color);
 
263
                Polyhedra* t=static_cast<Polyhedra*>(cm.get());
 
264
                vector<int> faceTri = t->GetSurfaceTriangulation();
 
265
 
 
266
                if (0) { 
 
267
                        glDisable(GL_LIGHTING);
 
268
                        glBegin(GL_LINES);
 
269
                                #define __ONEWIRE(a,b) glVertex3v(t->v[a]);glVertex3v(t->v[b])
 
270
                                        for(int tri=0; tri < (int) faceTri.size(); tri+=3) {__ONEWIRE(faceTri[tri],faceTri[tri+1]); __ONEWIRE(faceTri[tri],faceTri[tri+2]); __ONEWIRE(faceTri[tri+1],faceTri[tri+2]);}
 
271
                                #undef __ONEWIRE
 
272
                        glEnd();
 
273
                }
 
274
                else
 
275
                {
 
276
                        Vector3r centroid = t->GetCentroid();
 
277
                        Vector3r faceCenter, n;
 
278
                        glDisable(GL_CULL_FACE); glEnable(GL_LIGHTING);
 
279
                        glBegin(GL_TRIANGLES);
 
280
                                #define __ONEFACE(a,b,c) n=(t->v[b]-t->v[a]).cross(t->v[c]-t->v[a]); n.normalize(); faceCenter=(t->v[a]+t->v[b]+t->v[c])/3.; if((faceCenter-centroid).dot(n)<0)n=-n; glNormal3v(n); glVertex3v(t->v[a]); glVertex3v(t->v[b]); glVertex3v(t->v[c]);
 
281
                                        for(int tri=0; tri < (int) faceTri.size(); tri+=3) {__ONEFACE(faceTri[tri],faceTri[tri+1],faceTri[tri+2]);}
 
282
                                #undef __ONEFACE
 
283
                        glEnd();
 
284
                }
 
285
        }
 
286
#endif
 
287
 
 
288
//**********************************************************************************
 
289
//!Precompute data needed for rotating tangent vectors attached to the interaction
 
290
 
 
291
void PolyhedraGeom::precompute(const State& rbp1, const State& rbp2, const Scene* scene, const shared_ptr<Interaction>& c, const Vector3r& 
 
292
currentNormal, bool isNew, const Vector3r& shift2){
 
293
 
 
294
        if(!isNew) {
 
295
                orthonormal_axis = normal.cross(currentNormal);
 
296
                Real angle = scene->dt*0.5*normal.dot(rbp1.angVel + rbp2.angVel);
 
297
                twist_axis = angle*normal;}
 
298
        else twist_axis=orthonormal_axis=Vector3r::Zero(); 
 
299
        //Update contact normal
 
300
        normal=currentNormal;
 
301
        //Precompute shear increment
 
302
        Vector3r c1x = (contactPoint - rbp1.pos);
 
303
        Vector3r c2x = (contactPoint - rbp2.pos + shift2);
 
304
        Vector3r relativeVelocity = (rbp2.vel+rbp2.angVel.cross(c2x)) - (rbp1.vel+rbp1.angVel.cross(c1x));
 
305
        //keep the shear part only
 
306
        relativeVelocity = relativeVelocity-normal.dot(relativeVelocity)*normal;
 
307
        shearInc = relativeVelocity*scene->dt;
 
308
}
 
309
 
 
310
//**********************************************************************************
 
311
Vector3r& PolyhedraGeom::rotate(Vector3r& shearForce) const {
 
312
        // approximated rotations
 
313
        shearForce -= shearForce.cross(orthonormal_axis);
 
314
        shearForce -= shearForce.cross(twist_axis);
 
315
        //NOTE : make sure it is in the tangent plane? It's never been done before. Is it not adding rounding errors at the same time in fact?...
 
316
        shearForce -= normal.dot(shearForce)*normal;
 
317
        return shearForce;
 
318
}
 
319
 
 
320
 
 
321
//**********************************************************************************
 
322
/* Material law, physics */
 
323
 
 
324
void Ip2_PolyhedraMat_PolyhedraMat_PolyhedraPhys::go( const shared_ptr<Material>& b1
 
325
                                        , const shared_ptr<Material>& b2
 
326
                                        , const shared_ptr<Interaction>& interaction)
 
327
{
 
328
        if(interaction->phys) return;
 
329
        const shared_ptr<PolyhedraMat>& mat1 = YADE_PTR_CAST<PolyhedraMat>(b1);
 
330
        const shared_ptr<PolyhedraMat>& mat2 = YADE_PTR_CAST<PolyhedraMat>(b2);
 
331
        interaction->phys = shared_ptr<PolyhedraPhys>(new PolyhedraPhys());
 
332
        const shared_ptr<PolyhedraPhys>& contactPhysics = YADE_PTR_CAST<PolyhedraPhys>(interaction->phys);
 
333
        Real Kna        = mat1->Kn;
 
334
        Real Knb        = mat2->Kn;
 
335
        Real Ksa        = mat1->Ks;
 
336
        Real Ksb        = mat2->Ks;
 
337
        Real frictionAngle = std::min(mat1->frictionAngle,mat2->frictionAngle); 
 
338
        contactPhysics->tangensOfFrictionAngle = std::tan(frictionAngle);
 
339
        contactPhysics->kn = Kna*Knb/(Kna+Knb);
 
340
        contactPhysics->ks = Ksa*Ksb/(Ksa+Ksb);
 
341
};
 
342
 
 
343
//**************************************************************************************
 
344
#if 1
 
345
Real PolyhedraVolumetricLaw::getPlasticDissipation() {return (Real) plasticDissipation;}
 
346
void PolyhedraVolumetricLaw::initPlasticDissipation(Real initVal) {plasticDissipation.reset(); plasticDissipation+=initVal;}
 
347
Real PolyhedraVolumetricLaw::elasticEnergy()
 
348
{
 
349
        Real energy=0;
 
350
        FOREACH(const shared_ptr<Interaction>& I, *scene->interactions){
 
351
                if(!I->isReal()) continue;
 
352
                FrictPhys* phys = dynamic_cast<FrictPhys*>(I->phys.get());
 
353
                if(phys) {
 
354
                        energy += 0.5*(phys->normalForce.squaredNorm()/phys->kn + phys->shearForce.squaredNorm()/phys->ks);}
 
355
        }
 
356
        return energy;
 
357
}
 
358
#endif
 
359
 
 
360
 
 
361
//**************************************************************************************
 
362
// Apply forces on polyhedrons in collision based on geometric configuration
 
363
void PolyhedraVolumetricLaw::go(shared_ptr<IGeom>& ig, shared_ptr<IPhys>& ip, Interaction* I){
 
364
 
 
365
                if (!I->geom) {I->phys=shared_ptr<IPhys>(); return;} 
 
366
                const shared_ptr<PolyhedraGeom>& contactGeom(dynamic_pointer_cast<PolyhedraGeom>(I->geom));
 
367
                if(!contactGeom) {I->phys=shared_ptr<IPhys>(); return;} 
 
368
                const Body::id_t idA=I->getId1(), idB=I->getId2();
 
369
                const shared_ptr<Body>& A=Body::byId(idA), B=Body::byId(idB);
 
370
 
 
371
                PolyhedraPhys* phys = dynamic_cast<PolyhedraPhys*>(I->phys.get());      
 
372
 
 
373
                //erase the interaction when aAbB shows separation, otherwise keep it to be able to store previous separating plane for fast detection of separation 
 
374
                if (A->bound->min[0] >= B->bound->max[0] || B->bound->min[0] >= A->bound->max[0] || A->bound->min[1] >= B->bound->max[1] || B->bound->min[1] >= A->bound->max[1] || A->bound->min[2] >= B->bound->max[2] || B->bound->min[2] >= A->bound->max[2])  {
 
375
                        scene->interactions->requestErase(I);
 
376
                        return;
 
377
                }
 
378
                        
 
379
                //zero penetration depth means no interaction force
 
380
                if(!(contactGeom->penetrationVolume > 0) ) {I->phys=shared_ptr<IPhys>(); return;} 
 
381
                Vector3r normalForce=contactGeom->normal*contactGeom->penetrationVolume*phys->kn;
 
382
 
 
383
                //shear force: in case the polyhdras are separated and come to contact again, one should not use the previous shear force
 
384
                if (contactGeom->isShearNew)
 
385
                        shearForce = Vector3r::Zero();
 
386
                else
 
387
                        shearForce = contactGeom->rotate(shearForce);
 
388
 
 
389
                const Vector3r& shearDisp = contactGeom->shearInc;
 
390
                shearForce -= phys->ks*shearDisp;
 
391
                
 
392
                Real maxFs = normalForce.squaredNorm()*std::pow(phys->tangensOfFrictionAngle,2);
 
393
 
 
394
                if (likely(!scene->trackEnergy  && !traceEnergy)){//Update force but don't compute energy terms (see below))
 
395
                        // PFC3d SlipModel, is using friction angle. CoulombCriterion
 
396
                        if( shearForce.squaredNorm() > maxFs ){
 
397
                                Real ratio = sqrt(maxFs) / shearForce.norm();
 
398
                                shearForce *= ratio;}
 
399
                } else {
 
400
                        //almost the same with additional Vector3r instatinated for energy tracing, 
 
401
                        //duplicated block to make sure there is no cost for the instanciation of the vector when traceEnergy==false
 
402
                        if(shearForce.squaredNorm() > maxFs){
 
403
                                Real ratio = sqrt(maxFs) / shearForce.norm();
 
404
                                Vector3r trialForce=shearForce;//store prev force for definition of plastic slip
 
405
                                //define the plastic work input and increment the total plastic energy dissipated
 
406
                                shearForce *= ratio;
 
407
                                Real dissip=((1/phys->ks)*(trialForce-shearForce)).dot(shearForce);
 
408
                                if (traceEnergy) plasticDissipation += dissip;
 
409
                                else if(dissip>0) scene->energy->add(dissip,"plastDissip",plastDissipIx,false);
 
410
                        }
 
411
                        // compute elastic energy as well
 
412
                        scene->energy->add(0.5*(normalForce.squaredNorm()/phys->kn+shearForce.squaredNorm()/phys->ks),"elastPotential",elastPotentialIx,true);
 
413
                }
 
414
 
 
415
                Vector3r F = -normalForce-shearForce;   
 
416
                if (contactGeom->equivalentPenetrationDepth != contactGeom->equivalentPenetrationDepth) exit(1);
 
417
                scene->forces.addForce (idA,F);
 
418
                scene->forces.addForce (idB, -F);
 
419
                scene->forces.addTorque(idA, -(A->state->pos-contactGeom->contactPoint).cross(F));
 
420
                scene->forces.addTorque(idB, (B->state->pos-contactGeom->contactPoint).cross(F));       
 
421
        
 
422
                //needed to be able to acces interaction forces in other parts of yade
 
423
                phys->normalForce = normalForce;
 
424
                phys->shearForce = shearForce;
 
425
}
 
426
 
 
427
#endif // YADE_CGAL