← Back to team overview

yade-dev team mailing list archive

[svn] r1494 - in trunk: extra extra/clump gui gui/py

 

Author: eudoxos
Date: 2008-08-25 09:58:04 +0200 (Mon, 25 Aug 2008)
New Revision: 1494

Added:
   trunk/gui/py/_utils.cpp
Modified:
   trunk/extra/SimpleScene.cpp
   trunk/extra/clump/Shop.cpp
   trunk/extra/clump/Shop.hpp
   trunk/gui/SConscript
   trunk/gui/py/PythonUI_rc.py
   trunk/gui/py/eudoxos.py
   trunk/gui/py/ipython.py
   trunk/gui/py/utils.py
Log:
1. Reimplement some loop-intensive functions from yade.utils in c++ for better performance (as yade._utils, imported into yade.utils automatically - transparent to the user)
2. Add poisson's ratio and Young's modulus estimation in yade.eudoxos based on linear regressions of position?\226?\134?\146displacement mapping along different axes
3. Rename Shop::ElasticWaveTimestepEstimate to Shop::PWaveTimeStep, wrapped in yade.utils



Modified: trunk/extra/SimpleScene.cpp
===================================================================
--- trunk/extra/SimpleScene.cpp	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/extra/SimpleScene.cpp	2008-08-25 07:58:04 UTC (rev 1494)
@@ -156,7 +156,7 @@
 	rootBody->bodies->insert(sphere);
 	
 	//@
-	rootBody->dt=.2*Shop::ElasticWaveTimestepEstimate(rootBody);
+	rootBody->dt=.2*Shop::PWaveTimeStep(rootBody);
 
 	//@
 	return true;

Modified: trunk/extra/clump/Shop.cpp
===================================================================
--- trunk/extra/clump/Shop.cpp	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/extra/clump/Shop.cpp	2008-08-25 07:58:04 UTC (rev 1494)
@@ -1071,7 +1071,7 @@
 	{0.370512,0.415453,0.055970,0.010546},
 	{-1.,-1.,-1.,-1. } /* sentinel: non-positive radius */
 };
-
+#if 0
 Real Shop::ElasticWaveTimestepEstimate(shared_ptr<MetaBody> rootBody){
 	Real minDt=std::numeric_limits<Real>::infinity();
 	FOREACH(const shared_ptr<Body>& b, *rootBody->bodies){
@@ -1084,6 +1084,7 @@
 	}
 	return minDt;
 }
+#endif
 
 void Shop::GLDrawLine(Vector3r from, Vector3r to, Vector3r color){
 	glEnable(GL_LIGHTING); glColor3v(color);
@@ -1109,9 +1110,10 @@
 	glPopMatrix();
 
 }
-#if 0
-Real Shop::PWaveTimeStep(MetaBody* rb){
-	dt=std::numeric_limits<Real>::infinity();
+Real Shop::PWaveTimeStep(shared_ptr<MetaBody> _rb){
+	shared_ptr<MetaBody> rb=_rb;
+	if(!rb)rb=Omega::instance().getRootBody();
+	Real dt=std::numeric_limits<Real>::infinity();
 	FOREACH(const shared_ptr<Body>& b, *rb->bodies){
 		if(!b->physicalParameters || !b->geometricalModel) continue;
 		shared_ptr<ElasticBodyParameters> ebp=dynamic_pointer_cast<ElasticBodyParameters>(b->physicalParameters);
@@ -1122,4 +1124,3 @@
 	}
 	return dt;
 }
-#endif

Modified: trunk/extra/clump/Shop.hpp
===================================================================
--- trunk/extra/clump/Shop.hpp	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/extra/clump/Shop.hpp	2008-08-25 07:58:04 UTC (rev 1494)
@@ -79,9 +79,6 @@
 		//! Save spheres in the current simulation into a text file
 		static void saveSpheresToFile(string fileName);
 
-		//! Estimate timestep based on P-wave propagation speed
-		static Real ElasticWaveTimestepEstimate(shared_ptr<MetaBody>);
-
 		static void GLDrawLine(Vector3r from, Vector3r to, Vector3r color=Vector3r(1,1,1));
 		static void GLDrawArrow(Vector3r from, Vector3r to, Vector3r color=Vector3r(1,1,1));
 		static void GLDrawText(std::string text, Vector3r pos, Vector3r color=Vector3r(1,1,1));
@@ -101,8 +98,7 @@
 			static Vector3r& globalStiffness(body_id_t, MetaBody* mb=NULL);
 			static Vector3r& globalRStiffness(body_id_t, MetaBody* mb=NULL);
 		};
-		#if 0
-			Real PWaveTimeStep(MetaBody* rb);
-		#endif
 
+		//! Estimate timestep based on P-wave propagation speed
+		static Real PWaveTimeStep(shared_ptr<MetaBody> rb=shared_ptr<MetaBody>());
 };

Modified: trunk/gui/SConscript
===================================================================
--- trunk/gui/SConscript	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/gui/SConscript	2008-08-25 07:58:04 UTC (rev 1494)
@@ -52,7 +52,7 @@
 	# python modules are one level deeper so that you can say: from yade.wrapper import *
 	env.Install('$PREFIX/lib/yade$SUFFIX/gui/yade',[
 		env.SharedLibrary('wrapper',['py/yadeControl.cpp'],SHLIBPREFIX='',
-			LIBS=env['LIBS']+['yade-base','libboost_python','XMLFormatManager','yade-factory','yade-serialization','Shop',
+			LIBS=env['LIBS']+['libboost_python','XMLFormatManager','yade-factory','yade-serialization','Shop',
 				'BoundingVolumeMetaEngine',
 				'GeometricalModelMetaEngine',
 				'InteractingGeometryMetaEngine',
@@ -63,6 +63,8 @@
 				'ParallelEngine'
 			],
 			),
+		env.SharedLibrary('_utils',['py/_utils.cpp'],SHLIBPREFIX='',
+			LIBS=env['LIBS']+['Shop','libboost_python']),
 		env.SharedLibrary('log',['py/log.cpp'],SHLIBPREFIX=''),
 		env.File('__init__.py','py'),
 		env.File('utils.py','py'),

Modified: trunk/gui/py/PythonUI_rc.py
===================================================================
--- trunk/gui/py/PythonUI_rc.py	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/gui/py/PythonUI_rc.py	2008-08-25 07:58:04 UTC (rev 1494)
@@ -62,5 +62,3 @@
 		import yade.qt
 		yade.qt.close()
 	except ImportError: pass
-
-

Added: trunk/gui/py/_utils.cpp
===================================================================
--- trunk/gui/py/_utils.cpp	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/gui/py/_utils.cpp	2008-08-25 07:58:04 UTC (rev 1494)
@@ -0,0 +1,63 @@
+#include<yade/extra/Shop.hpp>
+#include<boost/python.hpp>
+#include<yade/core/MetaBody.hpp>
+#include<yade/core/Omega.hpp>
+#include<yade/pkg-common/Sphere.hpp>
+using namespace boost::python;
+
+python::tuple vec2tuple(const Vector3r& v){return boost::python::make_tuple(v[0],v[1],v[2]);};
+
+/* \todo implement groupMask */
+python::tuple aabbExtrema(){
+	Real inf=std::numeric_limits<Real>::infinity();
+	Vector3r minimum(inf,inf,inf),maximum(-inf,-inf,-inf);
+	FOREACH(const shared_ptr<Body>& b, *Omega::instance().getRootBody()->bodies){
+		shared_ptr<Sphere> s=dynamic_pointer_cast<Sphere>(b->geometricalModel); if(!s) continue;
+		Vector3r rrr(s->radius,s->radius,s->radius);
+		minimum=componentMinVector(minimum,b->physicalParameters->se3.position-rrr);
+		maximum=componentMaxVector(maximum,b->physicalParameters->se3.position+rrr);
+	}
+	return python::make_tuple(vec2tuple(minimum),vec2tuple(maximum));
+}
+
+python::tuple negPosExtremeIds(int axis, Real distFactor=1.1){
+	python::tuple extrema=aabbExtrema();
+	Real minCoord=extract<double>(extrema[0][axis])(),maxCoord=extract<double>(extrema[1][axis])();
+	python::list minIds,maxIds;
+	FOREACH(const shared_ptr<Body>& b, *Omega::instance().getRootBody()->bodies){
+		shared_ptr<Sphere> s=dynamic_pointer_cast<Sphere>(b->geometricalModel); if(!s) continue;
+		if(b->physicalParameters->se3.position[axis]-s->radius*distFactor<=minCoord) minIds.append(b->getId());
+		if(b->physicalParameters->se3.position[axis]+s->radius*distFactor>=maxCoord) maxIds.append(b->getId());
+	}
+	return python::make_tuple(minIds,maxIds);
+}
+BOOST_PYTHON_FUNCTION_OVERLOADS(negPosExtremeIds_overloads,negPosExtremeIds,1,2);
+
+python::tuple coordsAndDisplacements(int axis){
+	python::list retCoord,retDispl;
+	FOREACH(const shared_ptr<Body>&b, *Omega::instance().getRootBody()->bodies){
+		retCoord.append(b->physicalParameters->se3.position[axis]);
+		retDispl.append(b->physicalParameters->se3.position[axis]-b->physicalParameters->refSe3.position[axis]);
+	}
+	return python::make_tuple(retCoord,retDispl);
+}
+
+void setRefSe3(){
+	FOREACH(const shared_ptr<Body>& b, *Omega::instance().getRootBody()->bodies){
+		b->physicalParameters->refSe3.position=b->physicalParameters->se3.position;
+		b->physicalParameters->refSe3.orientation=b->physicalParameters->se3.orientation;
+	}
+}
+
+
+Real PWaveTimeStep(){return Shop::PWaveTimeStep();};
+
+BOOST_PYTHON_MODULE(_utils){
+	def("PWaveTimeStep",PWaveTimeStep);
+	def("aabbExtrema",aabbExtrema);
+	def("negPosExtremeIds",negPosExtremeIds,negPosExtremeIds_overloads(args("axis","distFactor")));
+	def("coordsAndDisplacements",coordsAndDisplacements);
+	def("setRefSe3",setRefSe3);
+}
+
+

Modified: trunk/gui/py/eudoxos.py
===================================================================
--- trunk/gui/py/eudoxos.py	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/gui/py/eudoxos.py	2008-08-25 07:58:04 UTC (rev 1494)
@@ -4,7 +4,39 @@
 # I doubt there functions will be useful for anyone besides me.
 #
 
+def estimatePoissonYoung(principalAxis,stress=0,plot=False):
+	"""Estimate Poisson's ration given the "principal" axis of straining.
+	For every base direction, homogenized strain is computed
+	(slope in linear regression on discrete function particle coordinate →
+	→ particle displacement	in the same direction as returned by
+	utils.coordsAndDisplacements) and, (if axis '0' is the strained 
+	axis) the poisson's ratio is given as -½(ε₁+ε₂)/ε₀.
 
+	Young's modulus is computed as σ/ε₀; if stress σ is not given (default 0),
+	the result is 0.
+	"""
+	dd=[] # storage for linear regression parameters
+	import pylab,numpy,stats
+	from yade import utils
+	for axis in [0,1,2]:
+		w,dw=utils.coordsAndDisplacements(axis)
+		l,ll=stats.linregress(w,dw)[0:2] # use only tangent and section
+		dd.append((l,ll,min(w),max(w)))
+		if plot: pylab.plot(w,dw,'.',label='xyz'[axis])
+	if plot:
+		for axis in [0,1,2]:
+			dist=dd[axis][-1]-dd[axis][-2]
+			c=numpy.linspace(dd[axis][-2]-.2*dist,dd[axis][-1]+.2*dist)
+			d=[dd[axis][0]*cc+dd[axis][1] for cc in c]
+			pylab.plot(c,d,label='interp '+'xyz'[axis])
+		pylab.legend()
+		pylab.show()
+	otherAxes=(principalAxis+1)%3,(principalAxis+2)%3
+	avgTransHomogenizedStrain=.5*(dd[otherAxes[0]][0]+dd[otherAxes[1]][0])
+	principalHomogenizedStrain=dd[principalAxis][0]
+	return -avgTransHomogenizedStrain/principalHomogenizedStrain,stress/principalHomogenizedStrain
+
+
 def oofemTextExport():
 	"""Export simulation data in text format 
 	

Modified: trunk/gui/py/ipython.py
===================================================================
--- trunk/gui/py/ipython.py	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/gui/py/ipython.py	2008-08-25 07:58:04 UTC (rev 1494)
@@ -16,4 +16,4 @@
 import IPython.ipapi
 ip=IPython.ipapi.get()
 ip.set_hook('complete_command',yade_completers,re_key='.*\\b[a-zA-Z0-9_]+\[["\'][^"\'\]]*$')
-
+ip.options.profile='yade'

Modified: trunk/gui/py/utils.py
===================================================================
--- trunk/gui/py/utils.py	2008-08-22 23:01:31 UTC (rev 1493)
+++ trunk/gui/py/utils.py	2008-08-25 07:58:04 UTC (rev 1494)
@@ -4,6 +4,8 @@
 #
 # 2008 © Václav Šmilauer <eudoxos@xxxxxxxx>
 
+#from yade._utils import *
+
 import math,random
 from yade.wrapper import *
 try: # use psyco if available
@@ -11,6 +13,10 @@
 	psyco.full()
 except ImportError: pass
 
+# c++ implementations for performance reasons
+from yade._utils import *
+
+
 def sphere(center,radius,density=1,young=30e9,poisson=.3,frictionAngle=0.5236,dynamic=True,wire=False,color=[1,1,1],physParamsClass='BodyMacroParameters'):
 	"""Create default sphere, with given parameters. Physical properties such as mass and inertia are calculated automatically."""
 	s=Body()
@@ -18,7 +24,7 @@
 	s.mold=InteractingGeometry('InteractingSphere',{'radius':radius,'diffuseColor':color})
 	V=(4./3)*math.pi*radius**3
 	inert=(2./5.)*V*density*radius**2
-	s.phys=PhysicalParameters(physParamsClass,{'se3':[center[0],center[1],center[2],1,0,0,0],'mass':V*density,'inertia':[inert,inert,inert],'young':young,'poisson':poisson,'frictionAngle':frictionAngle})
+	s.phys=PhysicalParameters(physParamsClass,{'se3':[center[0],center[1],center[2],1,0,0,0],'refSe3':[center[0],center[1],center[2],1,0,0,0],'mass':V*density,'inertia':[inert,inert,inert],'young':young,'poisson':poisson,'frictionAngle':frictionAngle})
 	s.bound=BoundingVolume('AABB',{'diffuseColor':[0,1,0]})
 	s['isDynamic']=dynamic
 	return s
@@ -29,29 +35,11 @@
 	b.shape=GeometricalModel('Box',{'extents':extents,'diffuseColor':color,'wire':wire,'visible':True})
 	b.mold=InteractingGeometry('InteractingBox',{'extents':extents,'diffuseColor':color})
 	mass=8*extents[0]*extents[1]*extents[2]*density
-	b.phys=PhysicalParameters(physParamsClass,{'se3':[center[0],center[1],center[2],orientation[0],orientation[1],orientation[2],orientation[3]],'mass':mass,'inertia':[mass*4*(extents[1]**2+extents[2]**2),mass*4*(extents[0]**2+extents[2]**2),mass*4*(extents[0]**2+extents[1]**2)],'young':young,'poisson':poisson,'frictionAngle':frictionAngle})
+	b.phys=PhysicalParameters(physParamsClass,{'se3':[center[0],center[1],center[2],orientation[0],orientation[1],orientation[2],orientation[3]],'refSe3':[center[0],center[1],center[2],orientation[0],orientation[1],orientation[2],orientation[3]],'mass':mass,'inertia':[mass*4*(extents[1]**2+extents[2]**2),mass*4*(extents[0]**2+extents[2]**2),mass*4*(extents[0]**2+extents[1]**2)],'young':young,'poisson':poisson,'frictionAngle':frictionAngle})
 	b.bound=BoundingVolume('AABB',{'diffuseColor':[0,1,0]})
 	b['isDynamic']=dynamic
 	return b
 
-def negPosExtremes(axis,distFactor=1.1):
-	"""Get 2 lists (negative and positive extremes) of sphere ids that are close to the boundary
-	in the direction of requested axis (0=x,1=y,2=z).
-
-	distFactor enlarges radius of the sphere, it can be considered 'extremal' even if it doesn't touch the extreme.
-	"""
-	inf=float('inf')
-	extremes=[inf,-inf]
-	ret=[[],[]]
-	o=Omega()
-	for b in o.bodies:
-		extremes[1]=max(extremes[1],+b.shape['radius']+b.phys['se3'][axis])
-		extremes[0]=min(extremes[0],-b.shape['radius']+b.phys['se3'][axis])
-	for b in o.bodies:
-		if b.phys['se3'][axis]-b.shape['radius']*distFactor<=extremes[0]: ret[0].append(b.id)
-		if b.phys['se3'][axis]+b.shape['radius']*distFactor>=extremes[1]: ret[1].append(b.id)
-	return ret
-
 def aabbWalls(extrema=None,thickness=None,oversizeFactor=1.5,**kw):
 	"""return 6 walls that will wrap existing packing;
 	extrema are extremal points of the AABB of the packing (will be calculated if not specified)
@@ -74,23 +62,13 @@
 			walls[-1].shape['visible']=True
 	return walls
 
-def aabbExtrema(consider=lambda body:True):
-	"""return min and max points of an aabb around spherical packing (non-spheres are ignored)"""
-	inf=float('inf')
-	minimum,maximum=[inf,inf,inf],[-inf,-inf,-inf]
-	o=Omega()
-	for b in o.bodies:
-		if consider(b) and b.shape.name=='Sphere':
-			minimum=[min(minimum[i],b.phys['se3'][i]-b.shape['radius']) for i in range(3)]
-			maximum=[max(maximum[i],b.phys['se3'][i]+b.shape['radius']) for i in range(3)]
-	return minimum,maximum
 
-def perpendicularArea(axis,consider=lambda body: True):
+def perpendicularArea(axis):
 	"""return area perpendicular to given axis (0=x,1=y,2=z) generated by bodies
 	for which the function consider returns True (defaults to returning True always)
 	and which is of the type "Sphere"
 	"""
-	ext=aabbExtrema(consider)
+	ext=aabbExtrema()
 	other=((axis+1)%3,(axis+2)%3)
 	return (ext[1][other[0]]-ext[0][other[0]])*(ext[1][other[1]]-ext[0][other[1]])
 
@@ -107,19 +85,6 @@
 		if onShapes and (b['isDynamic'] or not onlyDynamic): b.shape['diffuseColor']=color
 		if onMolds  and (b['isDynamic'] or not onlyDynamic): b.mold['diffuseColor']=color
 
-def PWaveTimeStep():
-	"""Estimate timestep by the elastic wave propagation speed (p-wave).
-	
-	Multiply the value returned by some safety factor < 1, since shear waves are not taken into account here."""
-	o=Omega()
-	dt=float('inf')
-	for b in o.bodies:
-		if not (b.phys and b.shape): continue
-		if not (b.phys.has_key('young') and b.shape.has_key('radius')): continue
-		density=b.phys['mass']/((4./3.)*math.pi*b.shape['radius']**3)
-		thisDt=b.shape['radius']/math.sqrt(b.phys['young']/density)
-		dt=min(dt,thisDt)
-	return dt
 
 def spheresFromFile(filename,scale=1.,wenjieFormat=False,**kw):
 	"""Load sphere coordinates from file, create spheres, insert them to the simulation.
@@ -150,3 +115,48 @@
 		out.write('%g\t%g\t%g\t%g\n'%(b.phys['se3'][0],b.phys['se3'][1],b.phys['se3'][2],b.shape['radius']))
 	out.close()
 
+def negPosExtremes(**kw): raise DeprecationWarning("negPosExtremes is deprecated, use negPosExtremalIds instead.")
+
+# reimplemented in _utils in c++ (results verified to be identical)
+if 0:
+	def negPosExtremes(axis,distFactor=1.1):
+		"""Get 2 lists (negative and positive extremes) of sphere ids that are close to the boundary
+		in the direction of requested axis (0=x,1=y,2=z).
+
+		distFactor enlarges radius of the sphere, it can be considered 'extremal' even if it doesn't touch the extreme.
+		"""
+		inf=float('inf')
+		extremes=[inf,-inf]
+		ret=[[],[]]
+		o=Omega()
+		for b in o.bodies:
+			extremes[1]=max(extremes[1],+b.shape['radius']+b.phys['se3'][axis])
+			extremes[0]=min(extremes[0],-b.shape['radius']+b.phys['se3'][axis])
+		for b in o.bodies:
+			if b.phys['se3'][axis]-b.shape['radius']*distFactor<=extremes[0]: ret[0].append(b.id)
+			if b.phys['se3'][axis]+b.shape['radius']*distFactor>=extremes[1]: ret[1].append(b.id)
+		return ret
+	def aabbExtrema(consider=lambda body:True):
+		"""return min and max points of an aabb around spherical packing (non-spheres are ignored)"""
+		inf=float('inf')
+		minimum,maximum=[inf,inf,inf],[-inf,-inf,-inf]
+		o=Omega()
+		for b in o.bodies:
+			if consider(b) and b.shape.name=='Sphere':
+				minimum=[min(minimum[i],b.phys['se3'][i]-b.shape['radius']) for i in range(3)]
+				maximum=[max(maximum[i],b.phys['se3'][i]+b.shape['radius']) for i in range(3)]
+		return minimum,maximum
+	def PWaveTimeStep():
+		"""Estimate timestep by the elastic wave propagation speed (p-wave).
+		
+		Multiply the value returned by some safety factor < 1, since shear waves are not taken into account here."""
+		o=Omega()
+		dt=float('inf')
+		for b in o.bodies:
+			if not (b.phys and b.shape): continue
+			if not (b.phys.has_key('young') and b.shape.has_key('radius')): continue
+			density=b.phys['mass']/((4./3.)*math.pi*b.shape['radius']**3)
+			thisDt=b.shape['radius']/math.sqrt(b.phys['young']/density)
+			dt=min(dt,thisDt)
+		return dt
+