← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 2600: New implementation of a particle model for wires and rockfall meshes (initial state)

 

------------------------------------------------------------
revno: 2600
committer: Klaus Thoeni <klaus.thoeni@xxxxxxxxx>
branch nick: yade
timestamp: Thu 2010-12-09 18:46:51 +1300
message:
  New implementation of a particle model for wires and rockfall meshes (initial state)
added:
  pkg/dem/WirePM.cpp
  pkg/dem/WirePM.hpp
modified:
  doc/references.bib


--
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
=== modified file 'doc/references.bib'
--- doc/references.bib	2010-11-03 15:50:02 +0000
+++ doc/references.bib	2010-12-09 05:46:51 +0000
@@ -14,6 +14,26 @@
 
 ***************************
 
+@Article{ Bertrand2008,
+	title = "Discrete element method (DEM) numerical modeling of double-twisted hexagonal mesh ",
+	author = "D. Bertrand and F. Nicot and P. Gotteland and S. Lambert",
+	journal = "Canadian Geotechnical Journal",
+	pages = "1104--1117",
+	volume = "45",
+	number = "8",
+	year = "2008"
+}
+
+@article{ Bertrand2005,
+	title = "Modelling a geo-composite cell using discrete analysis",
+	author = "D. Bertrand and F. Nicot and P. Gotteland and S. Lambert",
+	journal = "Computers and Geotechnics",
+	pages = "564--577",
+	volume = "32",
+	number = "8",
+	year = "2005"
+}
+
 @Article{ Chareyre2002a,
 	title = "Theoretical versus experimental modeling of the anchorage capacity of geotextiles in trenches.",
 	author = "B. Chareyre and L. Briancon and P. Villard",

=== added file 'pkg/dem/WirePM.cpp'
--- pkg/dem/WirePM.cpp	1970-01-01 00:00:00 +0000
+++ pkg/dem/WirePM.cpp	2010-12-09 05:46:51 +0000
@@ -0,0 +1,214 @@
+/* Klaus Thoeni 2010  */
+
+#include"WirePM.hpp"
+#include<yade/core/Scene.hpp>
+#include<yade/pkg/dem/ScGeom.hpp>
+#include<yade/core/Omega.hpp>
+
+YADE_PLUGIN((WireMat)(WireState)(WirePhys)(Ip2_WireMat_WireMat_WirePhys)(Law2_ScGeom_WirePhys_WirePM));
+
+
+/********************** WireMat ****************************/
+CREATE_LOGGER(WireMat);
+
+void WireMat::postLoad(WireMat&){
+	if(StrainStressValues.size() < 2)
+		throw invalid_argument("WireMat.StrainStressValues: at least two points must be given.");
+	if(StrainStressValues[0](0) == 0. && StrainStressValues[0](1) == 0.)
+		throw invalid_argument("WireMat.StrainStressValues: Definition must start with values greather then zero (strain>0,stress>0)");
+	// compute cross-sectin area
+	As = pow(diameter*0.5,2)*Mathr::PI;
+
+	// debug printout
+// 	Vector2r vbegin = *StrainStressValues.begin();
+// // 	Vector2r vbegin = StrainStressValues.front();
+// 	std::cerr << vbegin(0) << endl;
+// 	std::cerr << vbegin(1) << endl;
+// 	std::cerr << endl;
+// 
+// 	Real v0 = (*(StrainStressValues.begin()))(0);
+// 	Real v1 = (*StrainStressValues.begin())(1);
+// 	std::cerr << v0 << endl;
+// 	std::cerr << v1 << endl;
+
+	//BUG ????? postLoad is called twice,
+}
+
+
+/********************** Law2_ScGeom_WirePhys_WirePM ****************************/
+CREATE_LOGGER(Law2_ScGeom_WirePhys_WirePM);
+
+void Law2_ScGeom_WirePhys_WirePM::go(shared_ptr<IGeom>& ig, shared_ptr<IPhys>& ip, Interaction* contact){
+	ScGeom* geom = static_cast<ScGeom*>(ig.get()); 
+	WirePhys* phys = static_cast<WirePhys*>(ip.get());
+	const int &id1 = contact->getId1();
+	const int &id2 = contact->getId2();
+	Body* b1 = Body::byId(id1,scene).get();
+	Body* b2 = Body::byId(id2,scene).get();
+	
+	Real displN = geom->penetrationDepth; // NOTE: ScGeom->penetrationDepth>0 when spheres interpenetrate, and therefore, for wire always negative
+
+	/* get reference to values since values are updated for unloading */
+	vector<Vector2r> &DFValues = phys->DisplForceValues;
+	vector<Real> &kValues = phys->StiffnessValues;
+
+	Real D = displN - phys->initD; // interparticular distance is computed depending on the equilibrium distance
+
+	/* check whether the particles are linked or not */
+	if ( !phys->isLinked ) { // destroy the interaction before calculation
+		scene->interactions->requestErase(contact->getId1(),contact->getId2());
+		return;
+	}
+	if ( (phys->isLinked) && (D < DFValues.back()(0)) ) { // spheres are linked but failure because of reaching maximal admissible displacement 
+		phys->isLinked=false; 
+		// update body state with the number of broken links
+		WireState* st1=dynamic_cast<WireState*>(b1->state.get());
+		WireState* st2=dynamic_cast<WireState*>(b2->state.get());
+		st1->numBrokenLinks+=1;
+		st2->numBrokenLinks+=1;
+		scene->interactions->requestErase(contact->getId1(),contact->getId2());
+		return;
+	}
+	
+	/* compute normal force Fn */
+	Real Fn = 0.;
+	if ( D > DFValues[0](0) )
+		Fn = kValues[0] * (D-phys->Dplast);
+	else {
+		bool isDone = false;
+		unsigned int i = 0;
+		while (!isDone && i < DFValues.size()) { 
+			i++;
+			if ( D > DFValues[i](0) ) {
+				Fn = DFValues[i-1](1) + (D-DFValues[i-1](0))*kValues[i];
+				phys->Dplast = D - Fn/kValues[0];
+				isDone = true;
+				// update values for unloading
+				DFValues[0](0) = D;
+				DFValues[0](1) = Fn;
+			}
+		}
+	}
+	
+	TRVAR3( displN, D, Fn );
+
+	/* compression forces cannot be applied to wires */
+	if (Fn > 0.) Fn = 0.;
+	
+	phys->normalForce = Fn*geom->normal; // NOTE: normal is position2-position1 - It is directed from particle1 to particle2
+	        
+	State* st1 = Body::byId(id1,scene)->state.get();
+	State* st2 = Body::byId(id2,scene)->state.get();
+	
+	/* apply forces */
+	Vector3r f = phys->normalForce;
+	// these lines to adapt to periodic boundary conditions
+	if ( !scene->isPeriodic )  
+		applyForceAtContactPoint(f , geom->contactPoint , id2, st2->se3.position, id1, st1->se3.position);
+	else { // in scg we do not wrap particles positions, hence "applyForceAtContactPoint" cannot be used when scene is periodic
+		scene->forces.addForce(id1,-f);
+		scene->forces.addForce(id2,f);
+	}
+
+}
+
+CREATE_LOGGER(Ip2_WireMat_WireMat_WirePhys);
+
+void Ip2_WireMat_WireMat_WirePhys::go(const shared_ptr<Material>& b1, const shared_ptr<Material>& b2, const shared_ptr<Interaction>& interaction){
+	
+	/* avoid any updates if interactions which already exist */
+	if(interaction->phys) return; 
+	
+	ScGeom* geom=dynamic_cast<ScGeom*>(interaction->geom.get());
+	assert(geom);
+
+	/* set equilibrium distance, e.g. initial distance between particle (stress free state) */
+	shared_ptr<WirePhys> contactPhysics(new WirePhys()); 
+	contactPhysics->initD = geom->penetrationDepth;
+	contactPhysics->normalForce = Vector3r::Zero();
+
+	/* get values from material */
+	const shared_ptr<WireMat>& mat1 = YADE_PTR_CAST<WireMat>(b1);
+	const shared_ptr<WireMat>& mat2 = YADE_PTR_CAST<WireMat>(b2);
+
+	Real crossSection;
+	vector<Vector2r> SSValues;
+	
+	/* ckeck properties of interaction */
+	if ( mat1->id == mat2->id ) { // interaction of two bodies of the same material
+		crossSection = mat1->As;
+		SSValues = mat1->StrainStressValues;
+		if ( (mat1->isDoubleTwist) && (abs(interaction->getId1()-interaction->getId2())==1) ) // bodies which id differs by 1 are double twisted
+			contactPhysics->isDoubleTwist = true;
+		else
+			contactPhysics->isDoubleTwist = false;
+	}
+	else { // interaction of two bodies of two different materials, take weaker material and no double-twist
+		contactPhysics->isDoubleTwist = false;
+		if ( mat1->diameter <= mat2->diameter){
+			crossSection = mat1->As;
+			SSValues = mat1->StrainStressValues;
+		}
+		else {
+			crossSection = mat2->As;
+			SSValues = mat2->StrainStressValues;
+		}
+	}
+	
+	Real R1 = geom->radius1;
+	Real R2 = geom->radius2;
+	
+	Real l0 = R1 + R2 - contactPhysics->initD; // initial lenght of the wire (can be single or double twisted)
+
+	/* compute displscement-force values (tension negative since ScGem is used!) */
+	vector<Vector2r> DFValues;
+	for ( vector<Vector2r>::iterator it = SSValues.begin(); it != SSValues.end(); it++ ) {
+		Vector2r values = Vector2r::Zero();
+		values(0) = -(*it)(0)*l0;
+		values(1) = -(*it)(1)*crossSection;
+		DFValues.push_back(values);
+	}
+
+	/* compute elastic stiffness of single wire */
+	vector<Real> kValues;
+	Real k = DFValues[0](1) / DFValues[0](0);
+
+	/* update values if the interaction is double twiseted */
+	if ( contactPhysics->isDoubleTwist ) {
+		Real alpha = atan( l0 / (3.*Mathr::PI*mat1->diameter) );
+		Real kh = k * ( l0*mat1->diameter/crossSection ) / ( 48.*cos(alpha) * ( 41./9.*(1.+mat1->poisson) + 17./4.*pow(tan(alpha),2) ) );
+		k = 2. * ( mat1->lambdak*kh + (1-mat1->lambdak)*k );
+		Real F = k * DFValues[0](0);
+		Real mappingF = F/DFValues[0](1);
+		DFValues[0](1) = F;
+		for (unsigned int i = 1; i<DFValues.size(); i++) {
+			DFValues[i](0) *= mat1->lambdaEps;
+			DFValues[i](1) *= mappingF;
+		}
+	}
+	
+	/* store displscement-force values in physics */
+	contactPhysics->DisplForceValues = DFValues;
+
+	/* compute stiffness-values of wire */
+	contactPhysics->kn = k;
+	kValues.push_back(k);
+	for( unsigned int i = 1 ; i < DFValues.size()-1; i++ ) {
+		Real deltau = -DFValues[i](0) + DFValues[i-1](0);
+		Real deltaF = -DFValues[i](1) + DFValues[i-1](1);
+		k = deltaF/deltau;
+		kValues.push_back(k);
+	}
+	contactPhysics->StiffnessValues = kValues;
+
+	/* set particles as linked */
+	if ( (scene->iter < linkThresholdIteration))
+		contactPhysics->isLinked=true;
+	else
+		contactPhysics->isLinked=false;
+
+	interaction->phys = contactPhysics;
+
+}
+
+WirePhys::~WirePhys(){}

=== added file 'pkg/dem/WirePM.hpp'
--- pkg/dem/WirePM.hpp	1970-01-01 00:00:00 +0000
+++ pkg/dem/WirePM.hpp	2010-12-09 05:46:51 +0000
@@ -0,0 +1,106 @@
+/* Klaus Thoeni 2010 */
+
+/**
+=== OVERVIEW OF WirePM ===
+
+A particle model to simulate single wires and rockfall meshes (see Bertrad et al. 2005, Bertrad et al. 2008).
+
+Features of the interaction law:
+
+1. The law is designed for particles which do not touch. A link will be created by defining an interaction radius and running the threshold iteration.
+
+2. The contact law is for tension only. Compressive forces never exist between the particles. However, elastic unloading is considered.
+
+3. The force displacement curve which defines the interaction forces is piecewise linear and defined by the stress-strain curve of the wire material. Any piecewise linear curve can be used. 
+
+Remarks:
+- The contact law is new and still needs some testing :-) 
+*/
+
+#pragma once
+
+#include<yade/pkg/common/ElastMat.hpp>
+#include<yade/pkg/common/Dispatching.hpp>
+#include<yade/pkg/common/NormShearPhys.hpp>
+#include<yade/pkg/dem/ScGeom.hpp>
+
+/** This class holds information associated with each body state*/
+class WireState: public State {
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR(WireState,State,"Wire state information of each body.\n\nNone of that is used for computation (at least not now), only for post-processing.",
+		((int,numBrokenLinks,0,,"Number of broken links (e.g. number of wires connected to the body which are broken). [-]"))
+		,
+		createIndex();
+	);
+	REGISTER_CLASS_INDEX(WireState,State);
+};
+REGISTER_SERIALIZABLE(WireState);
+
+/** This class holds information associated with each body */
+class WireMat: public ElastMat {
+	public:
+		virtual shared_ptr<State> newAssocState() const { return shared_ptr<State>(new WireState); }
+		virtual bool stateTypeOk(State* s) const { return (bool)dynamic_cast<WireState*>(s); }
+		void postLoad(WireMat&);
+	DECLARE_LOGGER;
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR(WireMat,ElastMat,"Material for use with the Wire classes",
+		((Real,diameter,0.0027,," (Diameter of the single wire in [m] (the diameter is used to compute the cross-section area of the wire)."))
+		((vector<Vector2r>,StrainStressValues,,Attr::triggerPostLoad,"Piecewise linear definition of the stress-strain curve by set of points (strain[-]>0,stress[Pa]>0) for one single wire. Tension only is considered and the point (0,0) is not needed!"))
+		((bool,isDoubleTwist,false,,"Type of the mesh. If true two particles of the same material which body ids differ by one will be considered as double-twisted interaction."))
+		((Real,lambdaEps,0.4,,"Parameter between 0 and 1 to reduce the failure strain of the double-twisted wire (as used by [Bertrand2008]_). [-]"))
+		((Real,lambdak,0.21,,"Parameter between 0 and 1 to compute the elastic stiffness of the double-twisted wire (as used by [Bertrand2008]_): $\\k^D=2(\\lambda_k k_h + (1-\\lambda_k)k^S). [-]"))
+		((Real,As,0,Attr::readonly,"Cross-section area of a single wire used for the computation of the limit normal contact forces. [m²]"))
+		,
+		createIndex();
+	);
+	REGISTER_CLASS_INDEX(WireMat,ElastMat);
+};
+REGISTER_SERIALIZABLE(WireMat);
+
+/** This class holds information associated with each interaction */
+class WirePhys: public NormPhys {
+	public:
+		virtual ~WirePhys();
+	
+		YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(WirePhys,NormPhys,"Representation of a single interaction of the WirePM type, storage for relevant parameters",
+			((Real,initD,0,,"Equilibrium distance for particles. Computed as the initial inter-particular distance when particle are linked."))
+			((bool,isLinked,false,,"If true particles are linked and will interact. Interactions are linked automatically by the definition of the corresponding interaction radius. The value is false if the wire breaks (no more interaction)."))
+			((bool,isDoubleTwist,false,,"If true the properties of the interaction will be defined as a double-twisted wire."))
+			((vector<Vector2r>,DisplForceValues,,(Attr::readonly|Attr::noSave),"Defines the values for force-displacement curve."))
+			((vector<Real>,StiffnessValues,,(Attr::readonly|Attr::noSave),"Defines the values for the different stiffness (first value corresponds to elastic stiffness kn)."))
+			((Real,Dplast,0,Attr::readonly,"Plastic part of the inter-particular distance of the previous step. \n\n.. note::\n\t Only elastic displacements are reversible (the elastic stiffness is used for unloading) and compressive forces are inadmissible. The compressive stiffness is assumed to be equal to zero (see [Bertrand2005]_).\n\n.."))
+			,
+			createIndex();
+			,
+		);
+	DECLARE_LOGGER;
+	REGISTER_CLASS_INDEX(WirePhys,NormShearPhys);
+};
+REGISTER_SERIALIZABLE(WirePhys);
+
+/** 2d functor creating IPhys (Ip2) taking WireMat and WireMat of 2 bodies, returning type WirePhys */
+class Ip2_WireMat_WireMat_WirePhys: public IPhysFunctor{
+	public:
+		virtual void go(const shared_ptr<Material>& pp1, const shared_ptr<Material>& pp2, const shared_ptr<Interaction>& interaction);
+		
+		FUNCTOR2D(WireMat,WireMat);
+		DECLARE_LOGGER;
+		
+		YADE_CLASS_BASE_DOC_ATTRS(Ip2_WireMat_WireMat_WirePhys,IPhysFunctor,"Converts 2 :yref:`path<WireMat.path>` instances to :yref:`path<WirePhys.path>` with corresponding parameters.",
+			((int,linkThresholdIteration,1,,"Iteration to create the link."))
+		);
+};
+REGISTER_SERIALIZABLE(Ip2_WireMat_WireMat_WirePhys);
+
+/** 2d functor creating the interaction law (Law2) based on SphereContactGeometry (ScGeom) and WirePhys of 2 bodies, returning type WirePM */
+class Law2_ScGeom_WirePhys_WirePM: public LawFunctor{
+	public:
+		virtual void go(shared_ptr<IGeom>& _geom, shared_ptr<IPhys>& _phys, Interaction* I);
+		
+		FUNCTOR2D(ScGeom,WirePhys);
+
+		YADE_CLASS_BASE_DOC_ATTRS(Law2_ScGeom_WirePhys_WirePM,LawFunctor,"Constitutive law for the wire model.",
+			((int,linkThresholdIteration,1,,"Iteration to create the link."))
+		);
+	DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(Law2_ScGeom_WirePhys_WirePM);