70
73
YADE_PLUGIN((Ig2_GridNode_GridNode_GridNodeGeom6D));
76
bool Ig2_GridConnection_GridConnection_GridCoGridCoGeom::go( const shared_ptr<Shape>& cm1, const shared_ptr<Shape>& cm2, const State& state1, const State& state2, const Vector3r& shift2, const bool& force, const shared_ptr<Interaction>& c)
78
/*FIXME : /!\ Note that this geometry doesn't take care of any unwished duplicated contact or shear force following. /!\*/
79
GridConnection* conn1 = YADE_CAST<GridConnection*>(cm1.get());
80
GridConnection* conn2 = YADE_CAST<GridConnection*>(cm2.get());
81
State* stNode11 = conn1->node1->state.get();
82
State* stNode12 = conn1->node2->state.get();
83
State* stNode21 = conn2->node1->state.get();
84
State* stNode22 = conn2->node2->state.get();
86
if(conn1->node1==conn2->node1 || conn1->node1==conn2->node2 || conn1->node2==conn2->node1 || conn1->node2==conn2->node2){
87
//Two connections share at least one node, so they are contiguous => they must not interact.
90
//There could be a contact between to connections. Check this now.
91
bool isNew = !c->geom;
93
Vector3r A=stNode11->pos, a=stNode12->pos-A; //"A" is an extremity of conn1, "a" is the connection's segment.
94
Vector3r B=stNode21->pos, b=stNode22->pos-B; //"B" is an extremity of conn2, "b" is the connection's segment.
95
B+=shift2;//periodicity.
96
Vector3r N=a.cross(b); //"N" is orthogonal to "a" and "b". It means that "N" describes the common plan between a and b.
97
if(N.norm()>1e-14){ //If "a" and "b" are colinear, "N==0" and this is a special case.
98
Real dist=N.dot(B-A)/(N.norm()); //here "dist" is oriented, so it's sign depends on the orientation of "N" against "AB".
99
Vector3r pB=B-dist*(N/(N.norm())); //"pB" is the projection of the point "B" in the plane defined by his normal vector "N".
100
//Now we have pB, so we will compute the intersection of two segments into a plane.
101
int b0, b1; //2 base vectors used to compute the segment intersection. For more accuracy and to avoid det==0, don't choose the axis where N is max.
102
if(abs(N[0])<abs(N[1]) || abs(N[0])<abs(N[2])){b0=0 ; b1=abs(N[1])<abs(N[2])?1:2;}
104
Real det=a[b0]*b[b1]-a[b1]*b[b0];
106
//Now compute k and m, who are the parameters (relative position on the connections) of the intersection on conn1 ("A" and "a") and conn2 ("B" and "b") respectively.
107
k = (b[b1]*(pB[b0]-A[b0])+b[b0]*(A[b1]-pB[b1]))/det;
108
m = (a[b0]*(-pB[b1]+A[b1])+a[b1]*(pB[b0]-A[b0]))/det;
109
//This is a little bit tricky : if we haven't 0<k,m<1, it means that the intersection is not inside both segments,
110
//but the contact can occurs anyway between a connection's extremity and a connection's edge or between two connection's extremity.
111
//So the three next lines : don't modify k and m if (0<k,m<1), but modify them otherwise to compute later the right normal and penetrationDepth of the contact.
112
k = max(min( k,(Real)1.0),(Real)0.0);
113
m = max(min( (A+a*k-B).dot(b)/(pow(b.norm(),2.0)) ,(Real)1.0),(Real)0.0);
114
k = max(min( (B+b*m-A).dot(a)/(pow(a.norm(),2.0)) ,(Real)1.0),(Real)0.0);
116
else {//should never happen
118
cout<<"Error in Ig2_GridConnection_GridConnection_GridCoGridCoGeom : det=="<<det<<endl;
119
cout<<"Details : N="<<N<<" b0="<<b0<<" b1="<<b1<<" a="<<a<<" b="<<b<<endl;
122
else{ //this is a special case for perfectly colinear vectors ("a" and "b")
123
Real PA=(A-B).dot(b)/(b.norm()*b.norm()); PA=min((Real)1.0,max((Real)0.0,PA));
124
Real Pa=(A+a-B).dot(b)/(b.norm()*b.norm()); Pa=min((Real)1.0,max((Real)0.0,Pa));
125
Real PB=(B-A).dot(a)/(a.norm()*a.norm()); PB=min((Real)1.0,max((Real)0.0,PB));
126
Real Pb=(B+b-A).dot(a)/(a.norm()*a.norm()); Pb=min((Real)1.0,max((Real)0.0,Pb));
127
k=(PB+Pb)/2. ; m=(PA+Pa)/2.;
130
//Compute the geometry if "penetrationDepth" is positive.
131
double penetrationDepth = conn1->radius + conn2->radius - (A+k*a - (B+m*b)).norm();
132
shared_ptr<GridCoGridCoGeom> scm;
134
if(penetrationDepth<0)return false;
135
scm=shared_ptr<GridCoGridCoGeom>(new GridCoGridCoGeom());
138
else scm=YADE_PTR_CAST<GridCoGridCoGeom>(c->geom);
139
//k and m are used to compute almost everything...
140
//Fictious states (spheres) are generated at k or m of each connection, they will handle the contact.
141
scm->relPos1=k ; scm->relPos2=m;
142
scm->fictiousState1.pos=A + k*a ; scm->fictiousState2.pos=B + m*b;
143
scm->radius1 = conn1->radius ; scm->radius2 = conn2->radius;
144
scm->fictiousState1.vel = (1-k)*stNode11->vel + k*stNode12->vel;
145
scm->fictiousState2.vel = (1-m)*stNode21->vel + m*stNode22->vel;
146
Vector3r direction = a/(a.norm());
147
scm->fictiousState1.angVel = ((1-k)*stNode11->angVel + k*stNode12->angVel).dot(direction)*direction //twist part : interpolated
148
+ a.cross(stNode12->vel - stNode11->vel);// non-twist part : defined from nodes velocities
149
direction = b/(b.norm());
150
scm->fictiousState2.angVel = ((1-m)*stNode21->angVel + m*stNode22->angVel).dot(direction)*direction //twist part : interpolated
151
+ b.cross(stNode22->vel - stNode21->vel);// non-twist part : defined from nodes velocities
152
Vector3r normal= scm->fictiousState2.pos - scm->fictiousState1.pos;
153
normal/=normal.norm();
154
scm->contactPoint = scm->fictiousState1.pos + (scm->radius1-0.5*penetrationDepth)*normal;
155
scm->penetrationDepth=penetrationDepth;
156
scm->precompute(scm->fictiousState1,scm->fictiousState2,scene,c,normal,isNew,shift2,true);
160
bool Ig2_GridConnection_GridConnection_GridCoGridCoGeom::goReverse( const shared_ptr<Shape>& cm1, const shared_ptr<Shape>& cm2, const State& state1, const State& state2, const Vector3r& shift2, const bool& force, const shared_ptr<Interaction>& c)
162
return go(cm1,cm2,state2,state1,-shift2,force,c);
164
YADE_PLUGIN((Ig2_GridConnection_GridConnection_GridCoGridCoGeom));
74
167
bool Ig2_Sphere_GridConnection_ScGridCoGeom::go( const shared_ptr<Shape>& cm1,
404
497
YADE_PLUGIN((Law2_ScGridCoGeom_CohFrictPhys_CundallStrack));
499
void Law2_GridCoGridCoGeom_FrictPhys_CundallStrack::go(shared_ptr<IGeom>& ig, shared_ptr<IPhys>& ip, Interaction* contact){
500
int id1 = contact->getId1(), id2 = contact->getId2();
501
id_t id11 = (static_cast<GridConnection*>((&Body::byId(id1)->shape)->get()))->node1->getId();
502
id_t id12 = (static_cast<GridConnection*>((&Body::byId(id1)->shape)->get()))->node2->getId();
503
id_t id21 = (static_cast<GridConnection*>((&Body::byId(id2)->shape)->get()))->node1->getId();
504
id_t id22 = (static_cast<GridConnection*>((&Body::byId(id2)->shape)->get()))->node2->getId();
505
GridCoGridCoGeom* geom= static_cast<GridCoGridCoGeom*>(ig.get());
506
FrictPhys* phys = static_cast<FrictPhys*>(ip.get());
507
if(geom->penetrationDepth <0){
509
phys->shearForce = Vector3r::Zero();
510
phys->normalForce = Vector3r::Zero();}
511
else scene->interactions->requestErase(contact);
513
Real& un=geom->penetrationDepth;
514
phys->normalForce=phys->kn*std::max(un,(Real) 0)*geom->normal;
516
Vector3r& shearForce = geom->rotate(phys->shearForce);
517
const Vector3r& shearDisp = geom->shearIncrement();
518
shearForce -= phys->ks*shearDisp;
519
Real maxFs = phys->normalForce.squaredNorm()*std::pow(phys->tangensOfFrictionAngle,2);
521
if (!scene->trackEnergy && !traceEnergy){//Update force but don't compute energy terms (see below))
522
// PFC3d SlipModel, is using friction angle. CoulombCriterion
523
if( shearForce.squaredNorm() > maxFs ){
524
Real ratio = sqrt(maxFs) / shearForce.norm();
525
shearForce *= ratio;}
527
//almost the same with additional Vector3r instatinated for energy tracing,
528
//duplicated block to make sure there is no cost for the instanciation of the vector when traceEnergy==false
529
if(shearForce.squaredNorm() > maxFs){
530
Real ratio = sqrt(maxFs) / shearForce.norm();
531
Vector3r trialForce=shearForce;//store prev force for definition of plastic slip
532
//define the plastic work input and increment the total plastic energy dissipated
534
Real dissip=((1/phys->ks)*(trialForce-shearForce))/*plastic disp*/ .dot(shearForce)/*active force*/;
535
if (traceEnergy) plasticDissipation += dissip;
536
else if(dissip>0) scene->energy->add(dissip,"plastDissip",plastDissipIx,/*reset*/false);
538
// compute elastic energy as well
539
scene->energy->add(0.5*(phys->normalForce.squaredNorm()/phys->kn+phys->shearForce.squaredNorm()/phys->ks),"elastPotential",elastPotentialIx,/*reset at every timestep*/true);
541
Vector3r force = -phys->normalForce-shearForce;
542
Vector3r torque1 = (geom->radius1-0.5*geom->penetrationDepth)* geom->normal.cross(force);
543
Vector3r torque2 = (geom->radius2-0.5*geom->penetrationDepth)* geom->normal.cross(force);
545
scene->forces.addForce(id11,(1-geom->relPos1)*force);
546
scene->forces.addForce(id12,geom->relPos1*force);
547
scene->forces.addForce(id21,-(1-geom->relPos2)*force);
548
scene->forces.addForce(id22,-geom->relPos2*force);
550
scene->forces.addTorque(id11,(1-geom->relPos1)*torque1);
551
scene->forces.addTorque(id12,geom->relPos1*torque1);
552
scene->forces.addTorque(id21,(1-geom->relPos2)*torque2);
553
scene->forces.addTorque(id22,geom->relPos2*torque2);
555
YADE_PLUGIN((Law2_GridCoGridCoGeom_FrictPhys_CundallStrack));
406
556
//!################## Bounds #####################
408
558
void Bo1_GridConnection_Aabb::go(const shared_ptr<Shape>& cm, shared_ptr<Bound>& bv, const Se3r& se3, const Body* b){