← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 1972: Cohesionless Moment Rotation LLaw as implemented by Plassiard et al (2009). Verified

 

Merge authors:
  booncw (booncw)
------------------------------------------------------------
revno: 1972 [merge]
committer: CWBoon <booncw@xxxxxxxxxxx>
branch nick: trunk
timestamp: Sat 2010-01-16 15:05:03 +0000
message:
  Cohesionless Moment Rotation LLaw as implemented by Plassiard et al (2009).  Verified
added:
  pkg/dem/Engine/GlobalEngine/CohesionlessMomentRotation.cpp
  pkg/dem/Engine/GlobalEngine/CohesionlessMomentRotation.hpp


--
lp:yade
https://code.launchpad.net/~yade-dev/yade/trunk

Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-dev/yade/trunk/+edit-subscription.
=== added file 'pkg/dem/Engine/GlobalEngine/CohesionlessMomentRotation.cpp'
--- pkg/dem/Engine/GlobalEngine/CohesionlessMomentRotation.cpp	1970-01-01 00:00:00 +0000
+++ pkg/dem/Engine/GlobalEngine/CohesionlessMomentRotation.cpp	2010-01-16 15:03:01 +0000
@@ -0,0 +1,277 @@
+/* CWBoon@2010  booncw@xxxxxxxxxxx */
+
+
+#include"CohesionlessMomentRotation.hpp"
+#include<yade/core/Scene.hpp>
+#include<yade/pkg-dem/ScGeom.hpp>
+#include<yade/core/Omega.hpp>
+
+/* Contact law have been verified with Plassiard et al. (2009) : A spherical discrete element model: calibration procedure and incremental response */
+
+
+YADE_PLUGIN((Law2_SCG_MomentPhys_CohesionlessMomentRotation)(Ip2_BMP_BMP_MomentPhys)(MomentPhys));
+
+
+
+/********************** Law2_Dem3DofGeom_RockPMPhys_Rpm ****************************/
+CREATE_LOGGER(Law2_SCG_MomentPhys_CohesionlessMomentRotation);
+
+void Law2_SCG_MomentPhys_CohesionlessMomentRotation::go(shared_ptr<InteractionGeometry>& ig, shared_ptr<InteractionPhysics>& ip, Interaction* contact, Scene* rootBody){
+	
+	ScGeom* geom = static_cast<ScGeom*>(ig.get()); //InteractionGeometry
+	MomentPhys* phys = static_cast<MomentPhys*>(ip.get()); //InteractionPhysics
+	int id1 = contact->getId1(); //Id of body1
+        int id2 = contact->getId2(); //Id of body2
+	shared_ptr<BodyContainer>& bodies = rootBody->bodies;
+	Body* b1 = ( *bodies ) [id1].get();
+	Body* b2 = ( *bodies ) [id2].get();
+	Real dt = Omega::instance().getTimeStep(); //Get TimeStep
+
+
+	/*NormalForce */
+	Real displN=geom->penetrationDepth;  //get penetrationDepth from SCG
+	if (displN<0){rootBody->interactions->requestErase(contact->getId1(),contact->getId2()); return;}  //! NOTE: the sign for penetrationdepth is different from SCG and Dem3DofGeom
+	Real Fn =phys->kn*displN;   //scalar force
+	phys->normalForce= Fn*geom->normal; //vector force NOTE: normal is position2-position1.  Therefore it is directed from particle1 to particle2
+	
+
+	Vector3r axis;
+        Real angle;
+
+	
+	///////////////////////////////////////////////////////////////////////  SHEAR FORCE ///////////////////////////////////////////////
+				/*ShearForce*/
+				Vector3r& shearForce = phys->shearForce; //alias for phys->shearForce
+
+
+				/// Here is the code with approximated rotations ///
+				axis	 = phys->prevNormal.Cross(geom->normal);  //axis of rotation between previous and current
+				shearForce -= shearForce.Cross(axis); //minus shearForce that is perpendicular (outward) to contact (not tangent)
+				angle 	= dt*0.5*geom->normal.Dot(Body::byId(id1)->state->angVel+Body::byId(id2)->state->angVel); 
+				axis 	= angle*geom->normal;
+				shearForce -= shearForce.Cross(axis); //minus shearForce that is perpendicular outward to contact (not tangent)
+
+				/// Here is the code with exact rotations 		 ///
+				//Quaternionr q;
+				//1st imagine we have to rotate shearForce ON the x-y plane as a result of contact point rotation
+				//axis = phys->prevNormal.Cross(geom->normal); // axis of rotation of contact point
+				//angle = Mathr::ACos(geom->normal.Dot(phys->prevNormal)); //angle of rotation of contact point
+				//q.FromAxisAngle(axis,angle); //quaternion for rotation of contact point
+			       // shearForce = q*shearForce; //rotate shearForce from previous contact orientation to current contact orientation
+	
+				//Then imagine we have to find a direction by rotating  THROUGH the x-y plane, ABOUT the contact normal (i.e. axis).  The direction should be along the resultant angular velocity.
+				//angle	= dt*0.5*geom->normal.Dot(Body::byId(id1)->state->angVel + Body::byId(id1)->state->angVel); //angle of rotation about the contact normal
+				//axis	= geom->normal;
+				//q.FromAxisAngle(axis,angle);
+				//shearForce	= q*shearForce;
+				/// 							 ///
+
+	
+				Vector3r x = geom->contactPoint;
+				Vector3r c1x	= (x - b1->state->pos); //distance of contact point from centre1
+				Vector3r c2x	= (x - b2 ->state->pos); //distance of contact ponit from centre2	
+					/// The following definition of c1x and c2x is to avoid "granular ratcheting" 
+					///  (see F. ALONSO-MARROQUIN, R. GARCIA-ROJO, H.J. HERRMANN, 
+					///   "Micro-mechanical investigation of granular ratcheting, in Cyclic Behaviour of Soils and Liquefaction Phenomena",
+					///   ed. T. Triantafyllidis (Balklema, London, 2004), p. 3-10 - and a lot more papers from the same authors)
+
+
+				Vector3r _c1x_(0,0,0);
+				Vector3r _c2x_(0,0,0);
+
+				if (preventGranularRatcheting){
+					_c1x_	= geom->radius1*geom->normal; //vector radius1
+					_c2x_	= -geom->radius2*geom->normal; //vector radius2
+				}else{
+					_c1x_ = c1x;
+					_c2x_ = c2x;
+				}
+
+				Vector3r relativeVelocity	= (b2->state->vel + b2->state->angVel.Cross(_c2x_)) - (b1->state->vel + b1->state->angVel.Cross(_c1x_));
+				Vector3r shearVelocity	= relativeVelocity - geom->normal.Dot(relativeVelocity)*geom->normal; //First find the scalar value of normal velocity.  Then change it to a vector.  Then minus.
+				Vector3r shearDisplacement	= shearVelocity*dt; //in Dem3DofGeom displacementT() is cumulative
+				  
+				shearForce -= phys->ks*shearDisplacement; //shearForce is cumulative here because shearDisplacement is not cumulative.  See CundallStrack.hpp, it is different!
+      
+	
+	////////////////////////////////////////////////////////////   SHEAR FORCE END   ///////////////////////////////////////////////////////////////////////////////
+
+
+	/* Coulomb's Law */
+	Real maxFs = 0;
+        Real Fs = shearForce.Length(); //scalar
+	maxFs = std::max((Real) 0, Fn*phys->tanFrictionAngle); //Fn is scalar
+      	if ( Fs  > maxFs )
+	{
+	shearForce *= maxFs/Fs;
+	//if ( Fn<0 )  phys->normalForce = Vector3r::ZERO;
+	}
+
+	phys->shearForce = shearForce; //for recording purposes
+
+	/* Apply forces */
+	Vector3r f = phys->normalForce + shearForce;
+	rootBody->forces.addForce (id1,-f);
+	rootBody->forces.addForce (id2, f);
+	rootBody->forces.addTorque(id1,-(c1x).Cross(f)); //about axis perpendicular to normal and force
+	rootBody->forces.addTorque(id2, c2x.Cross(f));
+
+	/* Moment Rotation Law */
+	Quaternionr delta( b1->state->ori * phys->initialOrientation1.Conjugate() *phys->initialOrientation2 * b2->state->ori.Conjugate()); //relative orientation
+	Vector3r axisM;	// axis of rotation - this is the Moment direction UNIT vector.
+	Real angleM;	// angle represents the power of resistant ELASTIC moment
+	delta.ToAxisAngle(axisM,angleM);
+	if(angleM > Mathr::PI) angleM -= Mathr::TWO_PI; // angle is between 0 and 2*pi, but should be between -pi and pi 
+	
+	phys->cumulativeRotation = angleM;
+	//Real elasticMoment = phys->kr * std::abs(angleM); // positive value (*)	
+	//Vector3r moment = axisM * elasticMoment * (angleM<0.0?-1.0:1.0); // restore sign. (*)
+	
+
+	//Find angle*axis. That's all.  But first find angle about contact normal. Result is scalar. Axis is contact normal.
+	Real angle_twist(angleM * axisM.Dot(geom->normal) ); //rotation about normal
+	Vector3r axis_twist(angle_twist * geom->normal);
+	Vector3r moment_twist(axis_twist * phys->kr);
+	
+	Vector3r axis_bending(angleM*axisM - axis_twist); //total rotation minus rotation about normal
+	Vector3r moment_bending(axis_bending * phys->kr);
+
+	Vector3r moment = moment_twist + moment_bending;
+
+	Real radiusm = 0.5*(geom->radius1 + geom->radius2); //radius is used here
+	Real MomentMax = phys->Eta * radiusm* std::fabs(Fn);
+	Real scalarMoment = moment.Length();
+
+
+	if(scalarMoment > MomentMax) /*Plastic moment */
+	{
+		Real ratio=0;
+		ratio *= MomentMax/scalarMoment;
+		moment *= ratio;		
+		moment_twist *=  ratio;
+		moment_bending *= ratio;
+	}
+
+	phys->moment_twist = moment_twist;
+	phys->moment_bending = moment_bending;
+	
+	rootBody->forces.addTorque(id1,-moment);
+	rootBody->forces.addTorque(id2, moment);	
+	/// Moment law	END ///
+
+	phys->prevNormal = geom->normal;
+	
+}
+
+
+
+CREATE_LOGGER(Ip2_MomentMat_MomentMat_MomentPhys);
+
+void Ip2_MomentMat_MomentMat_MomentPhys::go(const shared_ptr<Material>& b1, const shared_ptr<Material>& b2, const shared_ptr<Interaction>& interaction){
+	
+	if(interaction->interactionPhysics) return; 
+
+	ScGeom* scg=dynamic_cast<ScGeom*>(interaction->interactionGeometry.get());
+			
+	assert(scg);
+
+	const shared_ptr<MomentMat>& sdec1 = YADE_PTR_CAST<MomentMat>(b1);
+	const shared_ptr<MomentMat>& sdec2 = YADE_PTR_CAST<MomentMat>(b2);
+			
+	shared_ptr<MomentPhys> contactPhysics(new MomentPhys()); 
+	//interaction->interactionPhysics = shared_ptr<MomentPhys>(new MomentPhys());		
+	//const shared_ptr<MomentPhys>& contactPhysics = YADE_PTR_CAST<MomentPhys>(interaction->interactionPhysics);
+
+	/* From interaction physics */
+	Real Ea 	= sdec1->young;
+	Real Eb 	= sdec2->young;
+	Real Va 	= sdec1->poisson;
+	Real Vb 	= sdec2->poisson;
+	Real fa 	= sdec1->frictionAngle;
+	Real fb 	= sdec2->frictionAngle;
+	Real etaA	= sdec1->eta;
+	Real etaB 	= sdec2->eta;
+
+	/* From interaction geometry */
+	Real Da= scg->radius1;
+	Real Db= scg->radius2;  			
+	
+	/* calculate stiffness */
+	Real Kn=0;
+	Real Ks=0;
+	Real Kr=0;	
+	
+	Real radiusm = (Da + Db)/2;
+	//Kr = Beta*Ks*radiusm*radiusm;  
+
+	if(userInputStiffness == true && useAlphaBeta == true){
+	Kn = 0.5*Knormal*radiusm;
+	Ks = Alpha*Knormal;
+	Ks = 0.5*Ks*radiusm;
+	Kr = Beta*Ks*radiusm*radiusm;  
+	}
+	else if (userInputStiffness == true && useAlphaBeta == false){//if userInputStiffness = true
+	Kn = Knormal;
+	Ks = Kshear;
+	Kr = Krotate;
+	}
+	else{ 
+	Kn = 2*Ea*Da*Eb*Db/(Ea*Da+Eb*Db);//harmonic average of two stiffnesses
+	Ks = 2*Ea*Da*Va*Eb*Db*Vb/(Ea*Da*Va+Eb*Db*Va);//harmonic average of two stiffnesses with ks=V*kn for each sphere
+	//Kr = Da*Db*Ks*2.0; // just like "2.0" above - it's an arbitrary parameter
+	Kr=0;	
+	}
+	
+	/* Pass values calculated from above to CSPhys */
+	contactPhysics->kn = Kn;
+	contactPhysics->ks = Ks;
+	contactPhysics->kr = Kr;
+	contactPhysics->Eta = std::min(etaA,etaB);
+	contactPhysics->frictionAngle		= std::min(fa,fb); 
+	contactPhysics->tanFrictionAngle	= std::tan(contactPhysics->frictionAngle); 
+	contactPhysics->initialOrientation1	= Body::byId(interaction->getId1())->state->ori;
+	contactPhysics->initialOrientation2	= Body::byId(interaction->getId2())->state->ori;
+	contactPhysics->prevNormal 		= scg->normal; //This is also done in the Contact Law.  It is not redundant because this class is only called ONCE!
+
+	interaction->interactionPhysics = contactPhysics;
+}
+
+
+
+/* Moment Phys */		
+MomentPhys::MomentPhys()
+{
+	createIndex();
+	frictionAngle = 0;
+	tanFrictionAngle = 0;
+	Eta = 0;
+	prevNormal = Vector3r(0,0,0);
+
+	moment_twist = Vector3r(0,0,0);
+	moment_bending = Vector3r(0,0,0);
+	
+	shear = Vector3r(0,0,0); //currently not used
+	cumulativeRotation =0; 
+// assign neutral value	
+	initialOrientation1 = Quaternionr(1.0,0.0,0.0,0.0);
+	initialOrientation2 = Quaternionr(1.0,0.0,0.0,0.0);
+	kr = 0;
+}
+
+MomentPhys::~MomentPhys(){}
+
+/* Ip2_BMP_BMP_MomentPhys */
+Ip2_MomentMat_MomentMat_MomentPhys::Ip2_MomentMat_MomentMat_MomentPhys()
+{
+	userInputStiffness = false;
+	useAlphaBeta = false;
+	Alpha = 0;
+	Beta = 0;	
+	Knormal = 0;
+	Krotate = 0;
+	Kshear= 0;
+
+}
+Ip2_MomentMat_MomentMat_MomentPhys::~Ip2_MomentMat_MomentMat_MomentPhys(){};
+
+

=== added file 'pkg/dem/Engine/GlobalEngine/CohesionlessMomentRotation.hpp'
--- pkg/dem/Engine/GlobalEngine/CohesionlessMomentRotation.hpp	1970-01-01 00:00:00 +0000
+++ pkg/dem/Engine/GlobalEngine/CohesionlessMomentRotation.hpp	2010-01-16 15:03:01 +0000
@@ -0,0 +1,70 @@
+#pragma once
+#include<yade/pkg-common/ElastMat.hpp>
+#include<yade/pkg-common/InteractionPhysicsFunctor.hpp>
+#include<yade/pkg-common/NormShearPhys.hpp>
+#include<yade/pkg-common/LawFunctor.hpp>
+#include<yade/pkg-dem/ScGeom.hpp>
+#include <set>
+#include <boost/tuple/tuple.hpp>
+
+
+class Law2_SCG_MomentPhys_CohesionlessMomentRotation: public LawFunctor{
+	public:
+		virtual void go(shared_ptr<InteractionGeometry>& _geom, shared_ptr<InteractionPhysics>& _phys, Interaction* I, Scene* rootBody);
+		bool preventGranularRatcheting;
+		Law2_SCG_MomentPhys_CohesionlessMomentRotation():preventGranularRatcheting(false){};
+		FUNCTOR2D(ScGeom,MomentPhys);
+		REGISTER_CLASS_AND_BASE(Law2_SCG_MomentPhys_CohesionlessMomentRotation,LawFunctor);
+		REGISTER_ATTRIBUTES(LawFunctor,/*nothing here*/);
+		DECLARE_LOGGER;	
+};
+REGISTER_SERIALIZABLE(Law2_SCG_MomentPhys_CohesionlessMomentRotation);
+
+
+class Ip2_MomentMat_MomentMat_MomentPhys: public InteractionPhysicsFunctor{
+	public:
+		bool userInputStiffness, useAlphaBeta; //for users to choose whether to input stiffness directly or use ratios to calculate Ks/Kn
+		Real Knormal, Kshear, Krotate; //allows user to input stiffness properties from triaxial test.  These will be passed to MomentPhys or NormShearPhys
+		Real Alpha, Beta; //Alpha is a ratio of Ks/Kn, Beta is a ratio to calculate Kr
+		Ip2_MomentMat_MomentMat_MomentPhys();
+		virtual ~Ip2_MomentMat_MomentMat_MomentPhys();
+		virtual void go(const shared_ptr<Material>& pp1, const shared_ptr<Material>& pp2, const shared_ptr<Interaction>& interaction);
+		REGISTER_ATTRIBUTES(InteractionPhysicsFunctor,(userInputStiffness)(useAlphaBeta)(Knormal)(Kshear)(Krotate)(Alpha)(Beta));
+		FUNCTOR2D(MomentMat,MomentMat);
+		REGISTER_CLASS_AND_BASE(Ip2_MomentMat_MomentMat_MomentPhys,InteractionPhysicsFunctor);
+		DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(Ip2_MomentMat_MomentMat_MomentPhys);
+
+
+class MomentPhys: public NormShearPhys {
+	private:
+	public:
+		Real frictionAngle, tanFrictionAngle, Eta;  
+		Vector3r prevNormal;
+		Vector3r shear;
+		Real cumulativeRotation;
+		Quaternionr	initialOrientation1,initialOrientation2;
+		Real		kr; // rolling stiffness
+		Vector3r	moment_twist,moment_bending;
+		MomentPhys();
+	
+	virtual ~MomentPhys();
+
+	REGISTER_ATTRIBUTES(NormShearPhys,(tanFrictionAngle) (frictionAngle) (prevNormal) (initialOrientation1) (initialOrientation2) (kr) (Eta)(moment_twist) (moment_bending) (shear)(cumulativeRotation));
+	REGISTER_CLASS_AND_BASE(MomentPhys,NormShearPhys);
+	REGISTER_CLASS_INDEX(MomentPhys,NormShearPhys);
+};
+REGISTER_SERIALIZABLE(MomentPhys);
+
+/** This class holds information associated with each body */
+class MomentMat: public FrictMat {
+	public:
+		Real eta; //It has to be stored in this class and not by ContactLaw, because users may want to change its values before/after isotropic compaction.
+		MomentMat(): eta(0) {createIndex();};
+		REGISTER_ATTRIBUTES(FrictMat, (eta));
+		REGISTER_CLASS_AND_BASE(MomentMat,FrictMat);
+		REGISTER_CLASS_INDEX(MomentMat,FrictMat);
+};
+REGISTER_SERIALIZABLE(MomentMat);
+