← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-pkg/yade/git-trunk] Rev 3840: Added a material model for mortar layer

 

------------------------------------------------------------
revno: 3840
committer: Jan Stransky <jan.stransky@xxxxxxxxxxx>
timestamp: Wed 2016-04-13 18:45:33 +0200
message:
  Added a material model for mortar layer
  
  added one reference
  added example script
added:
  examples/mortar/
  examples/mortar/matModel.py
  pkg/dem/MortarMat.cpp
  pkg/dem/MortarMat.hpp
modified:
  doc/references.bib


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

Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-pkg/yade/git-trunk/+edit-subscription
=== modified file 'doc/references.bib'
--- doc/references.bib	2016-03-24 22:08:26 +0000
+++ doc/references.bib	2016-04-13 16:45:33 +0000
@@ -892,3 +892,10 @@
   url = {http://docsdrive.com/pdfs/sciencepublications/jmssp/2005/8-11.pdf}
 }
 
+@misc{Lourenco1994,
+	author = {P B Lourenço},
+	title = {Analysis of masonry structures with interface elements. theory and applications},
+	year = {1994},
+	note = {Report No. 03-21-22-0-01, Delft University of Technology, Faculty of Civil Engineering},
+	url = {http://www.csarmento.uminho.pt/docs/ncr/de_civil/1994_Lourenco.pdf}
+}

=== added directory 'examples/mortar'
=== added file 'examples/mortar/matModel.py'
--- examples/mortar/matModel.py	1970-01-01 00:00:00 +0000
+++ examples/mortar/matModel.py	2016-04-13 16:45:33 +0000
@@ -0,0 +1,47 @@
+from yade import plot
+
+dt = 1e-5
+
+mortar = MortarMat()
+polyMat = PolyhedraMat()
+for mat in (mortar,polyMat):
+	O.materials.append(mat)
+
+def sim(angle):
+	O.reset()
+	O.dt = dt
+	bs = b1,b2 = [polyhedron(((-1,-1,-1),(+1,-1,-1),(-1,+1,-1),(+1,+1,-1),(-1,-1,+1),(+1,-1,+1),(-1,+1,+1),(+1,+1,+1)),material=mortar) for i in (0,1)]
+	b2.state.pos = (0,0,2)
+	for b in bs:
+		b.state.blockedDOFs = 'xyzXYZ'
+	O.bodies.append(bs)
+	#
+	factor=1.1
+	O.engines=[
+		ForceResetter(),
+		InsertionSortCollider([Bo1_Polyhedra_Aabb(aabbEnlargeFactor=factor,label='bo1')]),
+		InteractionLoop(
+			[Ig2_Polyhedra_Polyhedra_PolyhedraGeomOrScGeom(label='ig2')], 
+			[Ip2_PolyhedraMat_PolyhedraMat_PolyhedraPhys(),Ip2_MortarMat_MortarMat_MortarPhys()],
+			[Law2_PolyhedraGeom_PolyhedraPhys_Volumetric(),Law2_ScGeom_MortarPhys_Lourenco()]
+		),
+		NewtonIntegrator(),
+	]
+	ig2.ig2scGeom.interactionDetectionFactor = factor
+	O.step()
+	ig2.ig2scGeom.interactionDetectionFactor = bo1.aabbEnlargeFactor = 1
+	b2.state.vel = (sin(angle),0,cos(angle))
+	while len([i for i in O.interactions]):
+		sn,st = i.phys.sigmaN, i.phys.sigmaT.norm()
+		O.step()
+		if O.iter > 1e6:
+			raise RuntimeError, "TODO"
+	plot.addData(sn=sn,st=st)
+
+n = 50
+for i in xrange(n):
+	sim(i*pi/(n-1))
+
+plot.plots = {'sn':'st'}
+plot.matplotlib.pyplot.axes().set_aspect(1)
+p = plot.plot()

=== added file 'pkg/dem/MortarMat.cpp'
--- pkg/dem/MortarMat.cpp	1970-01-01 00:00:00 +0000
+++ pkg/dem/MortarMat.cpp	2016-04-13 16:45:33 +0000
@@ -0,0 +1,127 @@
+// 2016 © Jan Stránský <jan.stransky@xxxxxxxxxxx> 
+#include"MortarMat.hpp"
+
+
+YADE_PLUGIN((MortarMat)(Ip2_MortarMat_MortarMat_MortarPhys)(MortarPhys)(Law2_ScGeom_MortarPhys_Lourenco))
+
+
+CREATE_LOGGER(Ip2_MortarMat_MortarMat_MortarPhys);
+void Ip2_MortarMat_MortarMat_MortarPhys::go(const shared_ptr<Material>& material1, const shared_ptr<Material>& material2, const shared_ptr<Interaction>& interaction){
+	if (interaction->phys) return;
+	if (scene->iter >= cohesiveThresholdIter) return;
+	shared_ptr<MortarPhys> phys(new MortarPhys());
+	interaction->phys = phys;
+	MortarMat* mat1 = YADE_CAST<MortarMat*>(material1.get());
+	MortarMat* mat2 = YADE_CAST<MortarMat*>(material2.get());
+
+	if (mat1->id>=0 && mat1->id == mat2->id) {
+		#define _CPATTR(a) phys->a=mat1->a
+			_CPATTR(tensileStrength);
+			_CPATTR(compressiveStrength);
+			_CPATTR(cohesion);
+			_CPATTR(ellAspect);
+		#undef _CPATTR
+		phys->tangensOfFrictionAngle = std::tan(mat1->frictionAngle);
+	} else {
+		// averaging over both materials
+		#define _MINATTR(a) phys->a=std::min(mat1->a,mat2->a)
+		#define _AVGATTR(a) phys->a=.5*(mat1->a+mat2->a)
+			_MINATTR(tensileStrength);
+			_MINATTR(compressiveStrength);
+			_MINATTR(cohesion);
+			_AVGATTR(ellAspect);
+		#undef _AVGATTR
+		#undef _MINATTR
+		phys->tangensOfFrictionAngle = std::tan(.5*(mat1->frictionAngle+mat2->frictionAngle));
+		// E, G, kn, ks, crosssection, refPD, refLength to be computed in Law2
+	}
+}
+
+
+
+
+CREATE_LOGGER(MortarPhys);
+MortarPhys::~MortarPhys(){};
+
+
+
+
+
+
+
+/********************** Law2_ScGeom_MortarPhys_Lourenco ****************************/
+CREATE_LOGGER(Law2_ScGeom_MortarPhys_Lourenco);
+bool Law2_ScGeom_MortarPhys_Lourenco::go(shared_ptr<IGeom>& iGeom, shared_ptr<IPhys>& iPhys, Interaction* interaction){
+	ScGeom* geom=static_cast<ScGeom*>(iGeom.get());
+	MortarPhys* phys=static_cast<MortarPhys*>(iPhys.get());
+
+	Body::id_t id1 = interaction->getId1();
+ 	Body::id_t id2 = interaction->getId2();
+	const shared_ptr<Body> b1 = Body::byId(id1,scene);
+	const shared_ptr<Body> b2 = Body::byId(id2,scene);
+
+	/* just the first time */
+	if (interaction->isFresh(scene)) {
+		const Vector3r& pos1 = b1->state->pos;
+		const Vector3r& pos2 = b2->state->pos;
+		const Real& r1 = geom->refR1;
+		const Real& r2 = geom->refR2;
+		Vector3r shift2 = scene->isPeriodic? Vector3r(scene->cell->hSize*interaction->cellDist.cast<Real>()) : Vector3r::Zero();
+		phys->refLength = (pos2 - pos1 + shift2).norm();
+		Real minRad = r1 <= 0 ? r2 : r2 <= 0 ? r1 : std::min(r1,r2);
+		phys->crossSection = std::pow(minRad,2);
+		phys->refPD = geom->refR1 + geom->refR2 - phys->refLength;
+		const shared_ptr<MortarMat> mat1 = YADE_PTR_CAST<MortarMat>(b1->material);
+		const shared_ptr<MortarMat> mat2 = YADE_PTR_CAST<MortarMat>(b2->material);
+		const Real& E1(mat1->young);
+		const Real& E2(mat2->young);
+		const Real& n1(mat1->poisson);
+		const Real& n2(mat2->poisson);
+		phys->kn = 2*E1*r1*E2*r2/(E1*r1+E2*r2);
+		phys->ks = 2*E1*r1*n1*E2*r2*n2/(E1*r1*n1+E2*r2*n2);
+		phys->E = phys->kn * phys->refLength / phys->crossSection;
+		phys->G = phys->ks * phys->refLength / phys->crossSection;
+	}
+	
+	/* shorthands */
+	Real& epsN(phys->epsN);
+	Vector3r& epsT(phys->epsT);
+	const Real& E(phys->E); \
+	const Real& G(phys->G);
+	const Real& crossSection(phys->crossSection);
+	Real& sigmaN(phys->sigmaN);
+	Vector3r& sigmaT(phys->sigmaT);
+
+	epsN = - (-phys->refPD + geom->penetrationDepth) / phys->refLength;
+	geom->rotate(epsT);
+	epsT += geom->shearIncrement() / phys->refLength;
+
+	/* constitutive law */
+	sigmaN = E*epsN;
+	sigmaT = G*epsT;
+
+	Real st = sigmaT.norm();
+	bool cond1 = sigmaN - phys->tensileStrength > 0;
+	bool cond2 = st + sigmaN*phys->tangensOfFrictionAngle - phys->cohesion > 0;
+	bool cond3 = std::pow(sigmaN,2) + std::pow(phys->ellAspect*st,2) - std::pow(phys->compressiveStrength,2) > 0;
+	if (cond1 || cond2 || cond3) {
+		return false;
+	}
+   
+	phys->normalForce = -sigmaN*crossSection*geom->normal;
+	phys->shearForce = -sigmaT*crossSection;
+
+	State* s1 = b1->state.get();
+	State* s2 = b2->state.get();	
+
+	Vector3r f = -phys->normalForce - phys->shearForce;
+	if (!scene->isPeriodic) {
+		applyForceAtContactPoint(f, geom->contactPoint , id1, s1->se3.position, id2, s2->se3.position);
+	} else {
+		scene->forces.addForce(id1,f);
+		scene->forces.addForce(id2,-f);
+		scene->forces.addTorque(id1,(geom->radius1+.5*(phys->refPD-geom->penetrationDepth))*geom->normal.cross(f));
+		scene->forces.addTorque(id2,(geom->radius2+.5*(phys->refPD-geom->penetrationDepth))*geom->normal.cross(f));
+	}
+	return true;
+}

=== added file 'pkg/dem/MortarMat.hpp'
--- pkg/dem/MortarMat.hpp	1970-01-01 00:00:00 +0000
+++ pkg/dem/MortarMat.hpp	2016-04-13 16:45:33 +0000
@@ -0,0 +1,95 @@
+// 2016 © Jan Stránský <jan.stransky@xxxxxxxxxxx> 
+
+#pragma once
+
+#include<pkg/common/ElastMat.hpp>
+#include<pkg/common/Dispatching.hpp>
+#include<pkg/common/Sphere.hpp>
+#include<pkg/common/PeriodicEngines.hpp>
+#include<pkg/common/NormShearPhys.hpp>
+#include<pkg/dem/DemXDofGeom.hpp>
+#include<pkg/dem/ScGeom.hpp>
+#include<pkg/dem/FrictPhys.hpp>
+
+namespace py=boost::python;
+
+
+
+class MortarMat: public FrictMat {
+	public:
+		YADE_CLASS_BASE_DOC_ATTRS_CTOR(MortarMat,FrictMat,"Material for mortar interface, used in Ip2_MortarMat_MortarMat_MortarPhys and Law2_ScGeom_MortarPhys_Lourenco. Default values according to ",
+			((Real,young,1e9,,"Normal elastic modulus [Pa]"))
+			((Real,poisson,1,,"Shear to normal modulus ratio"))
+			((Real,frictionAngle,.25,,"Friction angle"))
+			//
+			((Real,tensileStrength,1e6,,"tensileStrength [Pa]"))
+			((Real,compressiveStrength,10e6,,"compressiveStrength [Pa]"))
+			((Real,cohesion,1e6,,"cohesion [Pa]"))
+			((Real,ellAspect,3,,"aspect ratio of elliptical 'cap'. Value >1 means the ellipse is longer along normal stress axis."))
+			,
+			createIndex();
+		);
+		REGISTER_CLASS_INDEX(MortarMat,FrictMat);
+};
+REGISTER_SERIALIZABLE(MortarMat);
+
+
+
+
+
+
+class MortarPhys: public FrictPhys {
+	public:
+		Real epsN, sigmaN;
+		Vector3r epsT, sigmaT;
+		virtual ~MortarPhys();
+		YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(MortarPhys,FrictPhys,"IPhys class containing parameters of MortarMat. Used by Law2_ScGeom_MortarPhys_Lourenco.",
+			((Real,tensileStrength,NaN,,"tensileStrength [Pa]"))
+			((Real,compressiveStrength,NaN,,"compressiveStrength [Pa]"))
+			((Real,cohesion,NaN,,"cohesion [Pa]"))
+			((Real,ellAspect,NaN,,"aspect ratio of elliptical 'cap'. Value >1 means the ellipse is longer along normal stress axis."))
+			((Real,crossSection,NaN,,"Crosssection of interaction"))
+			((Real,refLength,NaN,,"Initial length of interaction [m]"))
+			((Real,refPD,NaN,,"Reference penetration depth [m]"))
+			((Real,E,NaN,,"interaction Young's modulus [Pa]"))
+			((Real,G,NaN,,"interaction shear modulus [Pa]"))
+			, // ctors
+			epsT = Vector3r::Zero();
+			createIndex();
+			,
+			.def_readonly("epsN",&MortarPhys::epsN,"Current normal strain |yupdate|")
+			.def_readonly("epsT",&MortarPhys::epsT,"Current shear strain |yupdate|")
+			.def_readonly("sigmaN",&MortarPhys::sigmaN,"Current normal stress |yupdate|")
+			.def_readonly("sigmaT",&MortarPhys::sigmaT,"Current shear stress |yupdate|")
+		);
+		DECLARE_LOGGER;
+		REGISTER_CLASS_INDEX(MortarPhys,NormShearPhys);
+};
+REGISTER_SERIALIZABLE(MortarPhys);
+
+
+
+
+
+class Ip2_MortarMat_MortarMat_MortarPhys: public IPhysFunctor{
+	public:
+		virtual void go(const shared_ptr<Material>& material1, const shared_ptr<Material>& material2, const shared_ptr<Interaction>& interaction);
+		FUNCTOR2D(MortarMat,MortarMat);
+		DECLARE_LOGGER;
+		YADE_CLASS_BASE_DOC_ATTRS(Ip2_MortarMat_MortarMat_MortarPhys,IPhysFunctor,"Ip2 creating MortarPhys from two MortarMat instances.",
+			((long,cohesiveThresholdIter,2,,"Should new contacts be cohesive? They will before this iter#, they will not be afterwards. If <=0, they will never be."))
+		);
+};
+REGISTER_SERIALIZABLE(Ip2_MortarMat_MortarMat_MortarPhys);
+
+
+
+class Law2_ScGeom_MortarPhys_Lourenco: public LawFunctor{
+	public:
+		bool go(shared_ptr<IGeom>& iGeom, shared_ptr<IPhys>& iPhys, Interaction* interaction);
+		FUNCTOR2D(GenericSpheresContact,MortarPhys);
+		YADE_CLASS_BASE_DOC(Law2_ScGeom_MortarPhys_Lourenco,LawFunctor,"Material law for mortar layer according to [Lourenco1994]_. The contact behaves elastic until brittle failure when reaching strength envelope. The envelope has three parts.\n\nTensile with condition $\\sigma_N-f_t$.\n\nShear part with Mohr-Coulomb condition $|\\sigma_T|+\\sigma_N\\tan\\varphi-c$.\n\nCompressive part with condition $\\sigma_N^2+A^2\\sigma_T^2-f_c^2$\n\nThe main idea is to begin simulation with this model and when the contact is broken, to use standard non-cohesive Law2_PolyhedraGeom_PolyhedraPhys_Volumetric."
+		);
+		DECLARE_LOGGER;
+};
+REGISTER_SERIALIZABLE(Law2_ScGeom_MortarPhys_Lourenco);