← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 2125: 1. TriaixalStressController: originally compilation fix, but Luc was faster; Bruno, I tried to re...

 

------------------------------------------------------------
revno: 2125
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Thu 2010-04-01 08:53:09 +0200
message:
  1. TriaixalStressController: originally compilation fix, but Luc was faster; Bruno, I tried to replace on c-array with boost::array; if that works, you could use it for other c-arrays as well
  2. Add yield surface query function from python to Law2_..._Cpm
  3. Make plot support label translation via yade.plot.labels
  4. make chunkSize very small for debian; add strip for the optimized build
modified:
  SConstruct
  debian/rules
  lib/serialization/Serializable.hpp
  pkg/dem/Engine/PartialEngine/ThreeDTriaxialEngine.hpp
  pkg/dem/Engine/PartialEngine/TriaxialStateRecorder.hpp
  pkg/dem/Engine/PartialEngine/TriaxialStressController.hpp
  pkg/dem/meta/ConcretePM.cpp
  pkg/dem/meta/ConcretePM.hpp
  py/_eudoxos.cpp
  py/plot.py


--
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 'SConstruct'
--- SConstruct	2010-03-29 11:36:21 +0000
+++ SConstruct	2010-04-01 06:53:09 +0000
@@ -486,6 +486,7 @@
 	env.Append(FRAMEWORKS=['CoreServices','Carbon'])
 else:
 	env.Append(LINKFLAGS=['-rdynamic','-z','origin']) 
+	if not env['debug']: env.Append(SHLINKFLAGS=['-W,--strip-all'])
 
 # makes dynamic library loading easier (no LD_LIBRARY_PATH) and perhaps faster
 env.Append(RPATH=runtimeLibDirs)

=== modified file 'debian/rules'
--- debian/rules	2010-03-29 12:28:06 +0000
+++ debian/rules	2010-04-01 06:53:09 +0000
@@ -60,7 +60,7 @@
 	###   (a) use fakeroot-tcp instead of fakeroot
 	###   (b) use just 1 job
 	#debug build
-	NO_SCONS_GET_RECENT= scons buildPrefix=debian runtimePREFIX=/usr version=${VERSION} brief=0 chunkSize=-1 linkStrategy=monolithic features=vtk,gts,log4cxx,opengl,openmp exclude=snow PREFIX=debian/yade${_VERSION}-dbg/usr variant=-dbg optimize=0 march= debug=1 CPPPATH=/usr/include/vtk-5.0:/usr/include/vtk-5.2:/usr/include/vtk-5.4
+	NO_SCONS_GET_RECENT= scons buildPrefix=debian runtimePREFIX=/usr version=${VERSION} brief=0 chunkSize=4 linkStrategy=monolithic features=vtk,gts,log4cxx,opengl,openmp exclude=snow PREFIX=debian/yade${_VERSION}-dbg/usr variant=-dbg optimize=0 march= debug=1 CPPPATH=/usr/include/vtk-5.0:/usr/include/vtk-5.2:/usr/include/vtk-5.4 jobs=1
 	#optimized build
 	NO_SCONS_GET_RECENT= scons PREFIX=debian/yade${_VERSION}/usr variant='' optimize=1 debug=0
 	#install platform-independent files (docs, scripts, examples)
@@ -97,8 +97,7 @@
 #	dh_installinfo
 	dh_installman
 	dh_link
-	## do NOT use this!!! debug builds need symbols, optimized builds don't have them at all
-	#dh_strip
+	dh_strip --exclude=yade${_VERSION}-dbg   # don't strip the debug package
 	dh_compress
 	dh_fixperms
 #	dh_perl

=== modified file 'lib/serialization/Serializable.hpp'
--- lib/serialization/Serializable.hpp	2010-03-30 10:51:31 +0000
+++ lib/serialization/Serializable.hpp	2010-04-01 06:53:09 +0000
@@ -116,14 +116,13 @@
 
 // filter away 2nd element of a 2-tuple
 #define _STRIPDOC2(x,y,z) (BOOST_PP_TUPLE_ELEM(2,0,z))
-#define YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,attrs,deprec,extras) \
+#define _YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,attrs,deprec,extras) \
 	REGISTER_ATTRIBUTES_DEPREC(thisClass,baseClass,BOOST_PP_SEQ_FOR_EACH(_STRIPDOC2,thisClass,attrs),deprec) \
 	REGISTER_CLASS_AND_BASE(thisClass,baseClass) \
 	/* accessors for deprecated attributes, with warnings */ BOOST_PP_SEQ_FOR_EACH(_ACCESS_DEPREC,thisClass,deprec) \
 	/* python class registration */ virtual void pyRegisterClass(python::object _scope) const { if(!checkPyClassRegistersItself(#thisClass)) return; boost::python::scope thisScope(_scope); YADE_SET_DOCSTRING_OPTS; boost::python::class_<thisClass,shared_ptr<thisClass>,boost::python::bases<baseClass>,boost::noncopyable>(#thisClass,docString).def("__init__",python::raw_constructor(Serializable_ctor_kwAttrs<thisClass>)).def("clone",&Serializable_clone<thisClass>,python::arg("attrs")=python::dict()) BOOST_PP_SEQ_FOR_EACH(_PYATTR_DEF,thisClass,attrs) BOOST_PP_SEQ_FOR_EACH(_PYATTR_DEPREC_DEF,thisClass,deprec) extras ; }
 	// use later: void must_use_both_YADE_CLASS_BASE_DOC_ATTRS_and_YADE_PLUGIN(); 
-#define YADE_CLASS_BASE_DOC_ATTRS_PY(thisClass,baseClass,docString,attrs,extras) \
-	YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,attrs,extras)
+// #define YADE_CLASS_BASE_DOC_ATTRS_PY(thisClass,baseClass,docString,attrs,extras) YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,attrs,,extras)
 
 #define _STRIPDECL4(x,y,z) (( BOOST_PP_TUPLE_ELEM(4,1,z),BOOST_PP_TUPLE_ELEM(4,3,z) " :ydefault:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,2,z)) "`" ))
 // return type name; (for declaration)
@@ -134,13 +133,11 @@
 
 #define _DECLINI4(x,y,z) (( BOOST_PP_TUPLE_ELEM(4,1,z),BOOST_PP_TUPLE_ELEM(4,2,z) ))
 
-#define YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(thisClass,baseClass,docString,attrDecls,inits,ctor,extras) \
-	YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(thisClass,baseClass,docString,attrDecls,,inits,ctor,extras)
 // the most general here
 #define YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(thisClass,baseClass,docString,attrDecls,deprec,inits,ctor,extras) \
 	public: BOOST_PP_SEQ_FOR_EACH(_ATTR_DECL,~,attrDecls) /* attribute declarations */ \
 	thisClass() BOOST_PP_IF(BOOST_PP_SEQ_SIZE(inits attrDecls),:,) BOOST_PP_SEQ_FOR_EACH_I(_ATTR_INI,BOOST_PP_DEC(BOOST_PP_SEQ_SIZE(inits attrDecls)), inits BOOST_PP_SEQ_FOR_EACH(_DECLINI4,~,attrDecls)) { ctor ; } /* ctor, with initialization of defaults */ \
-	YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,BOOST_PP_SEQ_FOR_EACH(_STRIPDECL4,~,attrDecls),deprec,extras)
+	_YADE_CLASS_BASE_DOC_ATTRS_DEPREC_PY(thisClass,baseClass,docString,BOOST_PP_SEQ_FOR_EACH(_STRIPDECL4,~,attrDecls),deprec,extras)
 
 #define _STATATTR_PY(x,thisClass,z) .def_readwrite(BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,1,z)), &thisClass::BOOST_PP_TUPLE_ELEM(4,1,z), "|ystatic| :ydefault:`" BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(4,2,z)) "` " BOOST_PP_TUPLE_ELEM(4,3,z))
 #define _STATATTR_DECL(x,y,z) static BOOST_PP_TUPLE_ELEM(4,0,z) BOOST_PP_TUPLE_ELEM(4,1,z);
@@ -195,6 +192,7 @@
 #define YADE_CLASS_BASE_DOC_ATTRS(klass,base,doc,attrs)                 YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(klass,base,doc,attrs,,,)
 #define YADE_CLASS_BASE_DOC_ATTRS_CTOR(klass,base,doc,attrs,ctor)       YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(klass,base,doc,attrs,,ctor,)
 #define YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(klass,base,doc,attrs,ctor,py) YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(klass,base,doc,attrs,,ctor,py)
+#define YADE_CLASS_BASE_DOC_ATTRS_INIT_CTOR_PY(klass,base,doc,attrs,inits,ctor,py) YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(klass,base,doc,attrs,,inits,ctor,py)
 
 // for both fundamental and non-fundamental cases
 #define REGISTER_SERIALIZABLE_GENERIC(name,isFundamental) 						\

=== modified file 'pkg/dem/Engine/PartialEngine/ThreeDTriaxialEngine.hpp'
--- pkg/dem/Engine/PartialEngine/ThreeDTriaxialEngine.hpp	2010-03-31 16:24:16 +0000
+++ pkg/dem/Engine/PartialEngine/ThreeDTriaxialEngine.hpp	2010-04-01 06:53:09 +0000
@@ -50,7 +50,7 @@
 		"The engine perform a triaxial compression with a control in direction 'i' in stress (if stressControl_i) else in strain.\n\n"
 		"For a stress control the imposed stress is specified by 'sigma_i' with a 'max_veli' depending on 'strainRatei'. To obtain the same strain rate in stress control than in strain control you need to set 'wallDamping = 0.8'.\n"
 		" For a strain control the imposed strain is specified by 'strainRatei'.\n"
-		"With this engine you can also perform internal compaction by growing the size of particles by using :yref:TriaxialStressController::controlInternalStress . For that, just switch on 'internalCompaction=1' and fix sigma_iso=value of mean pressure that you want at the end of the internal compaction.\n"
+		"With this engine you can also perform internal compaction by growing the size of particles by using :yref:`TriaxialStressController::controlInternalStress`. For that, just switch on 'internalCompaction=1' and fix sigma_iso=value of mean pressure that you want at the end of the internal compaction.\n"
 		,
 		((Real, strainRate1,0,"target strain rate in direction 1 (./s)"))
 		((Real, currentStrainRate1,0,"current strain rate in direction 1 - converging to :yref:'ThreeDTriaxialEngine::strainRate1' (./s)"))

=== modified file 'pkg/dem/Engine/PartialEngine/TriaxialStateRecorder.hpp'
--- pkg/dem/Engine/PartialEngine/TriaxialStateRecorder.hpp	2010-03-31 16:24:16 +0000
+++ pkg/dem/Engine/PartialEngine/TriaxialStateRecorder.hpp	2010-04-01 06:53:09 +0000
@@ -32,7 +32,7 @@
 		virtual ~TriaxialStateRecorder ();
 		virtual void action();
 
-	YADE_CLASS_BASE_DOC_ATTRS_CTOR(TriaxialStateRecorder,Recorder,"Engine recording triaxial variables (needs :yref:TriaxialCompressionEngine or :yref:ThreeDTriaxialEngine present in the simulation).",
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR(TriaxialStateRecorder,Recorder,"Engine recording triaxial variables (needs :yref:`TriaxialCompressionEngin`e or :yref:`ThreeDTriaxialEngine` present in the simulation).",
 		((Real,porosity,1,"porosity of the packing [-]")), //Is it really needed to have this value as a serializable?
 		initRun=true;
 		);

=== modified file 'pkg/dem/Engine/PartialEngine/TriaxialStressController.hpp'
--- pkg/dem/Engine/PartialEngine/TriaxialStressController.hpp	2010-04-01 06:47:24 +0000
+++ pkg/dem/Engine/PartialEngine/TriaxialStressController.hpp	2010-04-01 06:53:09 +0000
@@ -12,6 +12,8 @@
 #include<yade/core/Scene.hpp>
 #include<yade/lib-base/Math.hpp>
 
+#include<boost/array.hpp>
+
 class Scene;
 class State;
 
@@ -37,7 +39,7 @@
 		int wall_id [6];
 //   		vector<int> wall_id;
 		//! Stores the value of the translation at the previous time step, stiffness, and normal
-		Vector3r	previousTranslation [6];
+		boost::array<Vector3r,6> previousTranslation;
 		//! The value of stiffness (updated according to stiffnessUpdateInterval) 
 		vector<Real>	stiffness;
 		Real 		strain [3];
@@ -144,32 +146,24 @@
 		((Real,meanStress,0,""))
 		((Real,volumetricStrain,0,""))
  		,
-//    		/* extra initializers */
-//    		//((wall_id,vector<int>(6,0)))
-//    		((wall_bottom_id,wall_id[0]))
-// 		((wall_top_id,wall_id[1]))
-// 		((wall_left_id,wall_id[2]))
-// 		((wall_right_id,wall_id[3]))
-// 		((wall_front_id,wall_id[4]))
-// 		((wall_back_id,wall_id[5]))
+			/* extra initializers */
 		,
    		/* constructor */
    		first = true;
-		stiffness.resize(6);
-		for (int i=0; i<6; ++i){
-// 			wall_id[i] = 0;
-			previousTranslation[i] = Vector3r::ZERO;
-			stiffness[i] = 0;
-			normal[i] = Vector3r::ZERO;
-			strain[i]=0;}
-		for (int i=0; i<3; ++i) strain[i] = 0;
-		normal[wall_bottom].Y()=1;
-		normal[wall_top].Y()=-1;
-		normal[wall_left].X()=1;
-		normal[wall_right].X()=-1;
-		normal[wall_front].Z()=-1;
-		normal[wall_back].Z()=1;	
-		porosity=1;
+			stiffness.resize(6);
+			previousTranslation.assign(Vector3r::ZERO);
+			for (int i=0; i<6; ++i){
+				normal[i] = stress[i] = force[i] = Vector3r::ZERO;
+				stiffness[i] = 0;
+			}
+			for (int i=0; i<3; ++i) strain[i] = 0;
+			normal[wall_bottom].Y()=1;
+			normal[wall_top].Y()=-1;
+			normal[wall_left].X()=1;
+			normal[wall_right].X()=-1;
+			normal[wall_front].Z()=-1;
+			normal[wall_back].Z()=1;	
+			porosity=1;
 		,
  		.def_readonly("porosity",&TriaxialStressController::porosity,"")
 		.def_readonly("boxVolume",&TriaxialStressController::boxVolume,"")

=== modified file 'pkg/dem/meta/ConcretePM.cpp'
--- pkg/dem/meta/ConcretePM.cpp	2010-03-27 22:18:10 +0000
+++ pkg/dem/meta/ConcretePM.cpp	2010-04-01 06:53:09 +0000
@@ -186,6 +186,7 @@
 			else epsN+=sigmaSoft/E+(BC->isoPrestress-sigmaSoft)/(E*relKnSoft);
 		}
 		CPM_MATERIAL_MODEL
+		//cerr<<"kappaD="<<kappaD<<", epsN="<<epsN<<", neverDamage="<<neverDamage<<", epsCrackOnset="<<epsCrackOnset<<", epsFracture="<<epsFracture<<", omega="<<omega<<"="<<funcG(kappaD,epsCrackOnset,epsFracture,neverDamage);
 	#else
 		// simplified public model
 		epsN+=BC->isoPrestress/E;
@@ -225,6 +226,16 @@
 	applyForceAtContactPoint(BC->normalForce+BC->shearForce, contGeom->contactPoint, I->getId1(), contGeom->se31.position, I->getId2(), contGeom->se32.position, scene);
 }
 
+Real Law2_Dem3DofGeom_CpmPhys_Cpm::yieldSigmaTMagnitude(Real sigmaN, Real omega, Real undamagedCohesion, Real tanFrictionAngle){
+#ifdef CPM_MATERIAL_MODEL
+	return CPM_YIELD_SIGMA_T_MAGNITUDE(sigmaN);
+#else
+	//return max((Real)0.,undamagedCohesion*(1-omega)-sigmaN*tanFrictionAngle);
+	throw std::runtime_error("Full CPM model not available in this build");
+#endif
+}
+
+
 #ifdef YADE_OPENGL
 	/********************** Gl1_CpmPhys ****************************/
 	#include<yade/lib-opengl/OpenGLWrapper.hpp>

=== modified file 'pkg/dem/meta/ConcretePM.hpp'
--- pkg/dem/meta/ConcretePM.hpp	2010-03-20 12:40:44 +0000
+++ pkg/dem/meta/ConcretePM.hpp	2010-04-01 06:53:09 +0000
@@ -53,6 +53,8 @@
 #include<yade/pkg-common/NormShearPhys.hpp>
 #include<yade/pkg-common/LawFunctor.hpp>
 
+namespace py=boost::python;
+
 /* Cpm state information about each body.
 None of that is used for computation (at least not now), only for post-processing.
 */
@@ -176,22 +178,22 @@
 		if(kappaD<epsCrackOnset || neverDamage) return 0;
 		return 1.-(epsCrackOnset/kappaD)*exp(-(kappaD-epsCrackOnset)/epsFracture);
 	}
+	//! return |sigmaT| at plastic surface for given sigmaN etc; not used by the law itself
+	Real yieldSigmaTMagnitude(Real sigmaN, Real omega, Real undamagedCohesion, Real tanFrictionAngle);
 
 	void go(shared_ptr<InteractionGeometry>& _geom, shared_ptr<InteractionPhysics>& _phys, Interaction* I, Scene* rootBody);
 
-	// utility functions
-	//! Update avgStress on all bodies (called from VTKRecorder and yade.eudoxos.particleConfinement)
-	//! Might be anywhere else as well (static method)
-	static void updateBodiesState(Scene*);
-
 	FUNCTOR2D(Dem3DofGeom,CpmPhys);
-	YADE_CLASS_BASE_DOC_ATTRS(Law2_Dem3DofGeom_CpmPhys_Cpm,LawFunctor,"Constitutive law for the :ref:`cpm-model`.",
+	YADE_CLASS_BASE_DOC_ATTRS_CTOR_PY(Law2_Dem3DofGeom_CpmPhys_Cpm,LawFunctor,"Constitutive law for the :ref:`cpm-model`.",
 		((int,yieldSurfType,2,"yield function: 0: mohr-coulomb (original); 1: parabolic; 2: logarithmic, 3: log+lin_tension, 4: elliptic, 5: elliptic+log"))
 		((Real,yieldLogSpeed,.1,"scaling in the logarithmic yield surface (should be <1 for realistic results; >=0 for meaningful results)"))
 		((Real,yieldEllipseShift,NaN,"horizontal scaling of the ellipse (shifts on the +x axis as interactions with +y are given)"))
 		((Real,omegaThreshold,((void)">=1. to deactivate, i.e. never delete any contacts",1.),"damage after which the contact disappears (<1), since omega reaches 1 only for strain →+∞"))
 		((Real,epsSoft,((void)"approximates confinement -20MPa precisely, -100MPa a little over, -200 and -400 are OK (secant)",-3e-3),"Strain at which softening in compression starts (non-negative to deactivate)"))
-		((Real,relKnSoft,.25,"Relative rigidity of the softening branch in compression (0=perfect elastic-plastic, <0 softening, >0 hardening)"))
+		((Real,relKnSoft,.25,"Relative rigidity of the softening branch in compression (0=perfect elastic-plastic, <0 softening, >0 hardening)")),
+		/*ctor*/,
+		.def("funcG",&Law2_Dem3DofGeom_CpmPhys_Cpm::funcG,(py::arg("kappaD"),py::arg("epsCrackOnset"),py::arg("epsFracture"),py::arg("neverDamage")=false),"Damage evolution law, evaluating the :math:`\\omega` parameter. :math:`\\kappa_D` is historically maximum strain, *epsCrackOnset* (:math:`\\varepsilon_0`) = :yref:`CpmMat.epsCrackOnset`, *epsFracture* = :yref:`CpmMat.epsFracture`; if *neverDamage* is ``True``, the value returned will always be 0 (no damage).")
+		.def("yieldSigmaTMagnitude",&Law2_Dem3DofGeom_CpmPhys_Cpm::yieldSigmaTMagnitude,(py::arg("sigmaN"),py::arg("omega"),py::arg("undamagedCohesion"),py::arg("tanFrictionAngle")),"Return radius of yield surface for given material and state parameters; uses attributes of the current instance (*yieldSurfType* etc), change them before calling if you need that.")
 	);
 	DECLARE_LOGGER;
 };

=== modified file 'py/_eudoxos.cpp'
--- py/_eudoxos.cpp	2010-03-22 12:32:38 +0000
+++ py/_eudoxos.cpp	2010-04-01 06:53:09 +0000
@@ -47,30 +47,6 @@
 }
 #endif
 
-/* yield surface for the CPM model; this is used only to make yield surface plot from python, for debugging */
-Real yieldSigmaTMagnitude(Real sigmaN, const shared_ptr<Law2_Dem3DofGeom_CpmPhys_Cpm>& functor){
-	#ifdef CPM_YIELD_SIGMA_T_MAGNITUDE
-		/* find first suitable interaction */
-		Scene* rootBody=Omega::instance().getScene().get();
-		shared_ptr<Interaction> I;
-		FOREACH(I, *rootBody->interactions){
-			if(I->isReal()) break;
-		}
-		if(!I->isReal()) {LOG_ERROR("No real interaction found, returning NaN!"); return NaN; }
-		CpmPhys* BC=dynamic_cast<CpmPhys*>(I->interactionPhysics.get());
-		if(!BC) {LOG_ERROR("Interaction physics is not a CpmPhys instance, returning NaN!"); return NaN;}
-		const Real &omega(BC->omega); const Real& undamagedCohesion(BC->undamagedCohesion); const Real& tanFrictionAngle(BC->tanFrictionAngle);
-		const Real& yieldLogSpeed(functor->yieldLogSpeed);
-		const int& yieldSurfType(functor->yieldSurfType);
-		const Real& yieldEllipseShift(functor->yieldEllipseShift);
-		return CPM_YIELD_SIGMA_T_MAGNITUDE(sigmaN);
-	#else
-		LOG_FATAL("CPM model not available in this build.");
-		throw;
-	#endif
-}
-
-
 // copied from _utils.cpp
 Vector3r tuple2vec(const py::tuple& t){return Vector3r(py::extract<double>(t[0])(),py::extract<double>(t[1])(),py::extract<double>(t[2])());}
 
@@ -182,7 +158,6 @@
 	import_array();
 	YADE_SET_DOCSTRING_OPTS;
 	py::def("velocityTowardsAxis",velocityTowardsAxis,velocityTowardsAxis_overloads(py::args("axisPoint","axisDirection","timeToAxis","subtractDist","perturbation")));
-	py::def("yieldSigmaTMagnitude",yieldSigmaTMagnitude);
 	// def("spiralSphereStresses2d",spiralSphereStresses2d,(python::arg("dH_dTheta"),python::arg("axis")=2));
 	py::def("particleConfinement",particleConfinement);
 	py::def("testNumpy",testNumpy);

=== modified file 'py/plot.py'
--- py/plot.py	2010-03-09 14:20:36 +0000
+++ py/plot.py	2010-04-01 06:53:09 +0000
@@ -16,13 +16,13 @@
 
 data={} # global, common for all plots: {'name':[value,...],...}
 plots={} # dictionary x-name -> (yspec,...), where yspec is either y-name or (y-name,'line-specification')
-plotsFilled={} # same as plots but with standalone plot specs filled to tuples (used internally only)
-plotLines={} # dictionary x-name -> Line2d objects (that hopefully still correspond to yspec in plots)
-needsFullReplot=True
+"Dictionary converting names in data to human-readable names (TeX names, for instance); if a variable is not specified, it is left untranslated."
+labels={}
+#plotLines={} # dictionary x-name -> Line2d objects (that hopefully still correspond to yspec in plots)
 
 def reset():
-	global data, plots, plotsFilled, plotLines, needsFullReplot
-	data={}; plots={}; plotsFilled={}; plotLines={}; needsFullReplot=True; 
+	global data, plots, labels # plotLines
+	data={}; plots={}; # plotLines={};
 	pylab.close('all')
 
 def resetData():
@@ -31,32 +31,18 @@
 
 # we could have a yplot class, that would hold: (yspec,...), (Line2d,Line2d,...) ?
 
-
 plotDataCollector=None
 from yade.wrapper import *
 
-# no longer used
-maxDataLen=1000
-## no longer used
-def reduceData(l):
-	"""If we have too much data, take every second value and double the step for DateGetterEngine. This will keep the samples equidistant.
-	"""
-	if l>maxDataLen:
-		global plotDataCollector
-		if not plotDataCollector: plotDataCollector=O.labeledEngine('plotDataCollector') # will raise RuntimeError if not found
-		if plotDataCollector.mayStretch: # may we double the period without getting over limits?
-			plotDataCollector.stretchFactor=2. # just to make sure
-			print "Reducing data: %d > %d"%(l,maxDataLen)
-			for d in data: data[d]=data[d][::2]
-			for attr in ['virtPeriod','realPeriod','iterPeriod']:
-				if(plotDataCollector[attr]>0): plotDataCollector[attr]=2*plotDataCollector[attr]
-
 def splitData():
 	"Make all plots discontinuous at this point (adds nan's to all data fields)"
 	addData({})
 
-
 def reverseData():
+	"""Reverse yade.plot.data order.
+	
+	Useful for tension-compression test, where the initial (zero) state is loaded and, to make data continuous, last part must *end* in the zero state.
+	"""
 	for k in data: data[k].reverse()
 
 def addData(*d_in,**kw):
@@ -81,63 +67,61 @@
 		if name in d: data[name].append(d[name]) #numpy.append(data[name],[d[name]],1)
 		else: data[name].append(nan)
 
-def addPointTypeSpecifier(o):
+def _addPointTypeSpecifier(o):
 	"""Add point type specifier to simple variable name"""
 	if type(o) in [tuple,list]: return o
 	else: return (o,'')
-def tuplifyYAxis(pp):
+def _tuplifyYAxis(pp):
 	"""convert one variable to a 1-tuple"""
 	if type(pp) in [tuple,list]: return pp
 	else: return (pp,)
-
-def show(): plot()
-
-def plot():
-	pylab.ion() ## # no interactive mode (hmmm, I don't know why actually...)
+def _xlateLabel(l):
+	"Return translated label; return l itself if not in the labels dict."
+	global labels
+	if l in labels.keys(): return labels[l]
+	else: return l
+
+def plot(noShow=False):
+	"""Show current plot, returning the figure object.
+	
+	If *noShow* is true, figure will not be shown on screen at all.
+	
+	You can use 
+	
+		>>> from yade import plot
+		>>> plot.plot(noShow=True).saveFig('someFile.pdf')
+		
+	to save the figure to file automatically.
+	"""
+	if not noShow: pylab.ion() ## # no interactive mode (hmmm, I don't know why actually...)
 	for p in plots:
 		pylab.figure()
-		plots_p=[addPointTypeSpecifier(o) for o in tuplifyYAxis(plots[p])]
-		plotsFilled[p]=plots_p
+		plots_p=[_addPointTypeSpecifier(o) for o in _tuplifyYAxis(plots[p])]
 		plots_p_y1,plots_p_y2=[],[]; y1=True
 		for d in plots_p:
 			if d[0]=='|||':
 				y1=False; continue
 			if y1: plots_p_y1.append(d)
 			else: plots_p_y2.append(d)
-		plotLines[p]=pylab.plot(*sum([[data[p],data[d[0]],d[1]] for d in plots_p_y1],[]))
-		pylab.legend([_p[0] for _p in plots_p_y1],loc=('upper left' if len(plots_p_y2)>0 else 'best'))
-		pylab.ylabel(','.join([_p[0] for _p in plots_p_y1]))
+		#plotLines[p]=
+		pylab.plot(*sum([[data[p],data[d[0]],d[1]] for d in plots_p_y1],[]))
+		pylab.legend([_xlateLabel(_p[0]) for _p in plots_p_y1],loc=('upper left' if len(plots_p_y2)>0 else 'best'))
+		pylab.ylabel(','.join([_xlateLabel(_p[0]) for _p in plots_p_y1]))
 		if len(plots_p_y2)>0:
 			# try to move in the color palette a little further (magenta is 5th): r,g,b,c,m,y,k
 			origLinesColor=pylab.rcParams['lines.color']; pylab.rcParams['lines.color']='m'
 			# create the y2 axis
 			pylab.twinx()
-			plotLines[p]+=[pylab.plot(*sum([[data[p],data[d[0]],d[1]] for d in plots_p_y2],[]))]
-			pylab.legend([_p[0] for _p in plots_p_y2],loc='upper right')
+			#plotLines[p]+=
+			[pylab.plot(*sum([[data[p],data[d[0]],d[1]] for d in plots_p_y2],[]))]
+			pylab.legend([_xlateLabel(_p[0]) for _p in plots_p_y2],loc='upper right')
 			pylab.rcParams['lines.color']=origLinesColor
-			pylab.ylabel(','.join([_p[0] for _p in plots_p_y2]))
-		pylab.xlabel(p)
+			pylab.ylabel(','.join([_xlateLabel(_p[0]) for _p in plots_p_y2]))
+		pylab.xlabel(_xlateLabel(p))
 		if 'title' in O.tags.keys(): pylab.title(O.tags['title'])
-	pylab.show()
+	if not noShow: pylab.show()
+	return pylab.gcf() # return current figure
 updatePeriod=0
-def periodicUpdate(period):
-	import time
-	global updatePeriod
-	while updatePeriod>0:
-		doUpdate()
-		time.sleep(updatePeriod)
-def startUpdate(period=10):
-	global updatePeriod
-	updatePeriod=period
-	import threading
-	threading.Thread(target=periodicUpdate,args=(period,),name='Thread-update').start()
-def stopUpdate():
-	global updatePeriod
-	updatePeriod=0
-def doUpdate():
-	pylab.close('all')
-	plot()
-
 
 def saveGnuplot(baseName,term='wxt',extension=None,timestamp=False,comment=None,title=None,varData=False):
 	"""baseName: used for creating baseName.gnuplot (command file for gnuplot),
@@ -174,10 +158,10 @@
 	i=0
 	for p in plots:
 		# print p
-		plots_p=[addPointTypeSpecifier(o) for o in tuplifyYAxis(plots[p])]
+		plots_p=[_addPointTypeSpecifier(o) for o in _tuplifyYAxis(plots[p])]
 		if term in ['wxt','x11']: fPlot.write("set term %s %d persist\n"%(term,i))
 		else: fPlot.write("set term %s; set output '%s.%d.%s'\n"%(term,baseNameNoPath,i,extension))
-		fPlot.write("set xlabel '%s'\n"%p)
+		fPlot.write("set xlabel '%s'\n"%_xlateLabel(p))
 		fPlot.write("set grid\n")
 		fPlot.write("set datafile missing 'nan'\n")
 		if title: fPlot.write("set title '%s'\n"%title)
@@ -187,13 +171,13 @@
 				y1=False; continue
 			if y1: plots_y1.append(d)
 			else: plots_y2.append(d)
-		fPlot.write("set ylabel '%s'\n"%(','.join([_p[0] for _p in plots_y1]))) 
+		fPlot.write("set ylabel '%s'\n"%(','.join([_xlateLabel(_p[0]) for _p in plots_y1]))) 
 		if len(plots_y2)>0:
-			fPlot.write("set y2label '%s'\n"%(','.join([_p[0] for _p in plots_y2])))
+			fPlot.write("set y2label '%s'\n"%(','.join([_xlateLabel(_p[0]) for _p in plots_y2])))
 			fPlot.write("set y2tics\n")
 		ppp=[]
-		for pp in plots_y1: ppp.append(" %s using %d:%d title '← %s(%s)' with lines"%(dataFile,vars.index(p)+1,vars.index(pp[0])+1,pp[0],p,))
-		for pp in plots_y2: ppp.append(" %s using %d:%d title '%s(%s) →' with lines axes x1y2"%(dataFile,vars.index(p)+1,vars.index(pp[0])+1,pp[0],p,))
+		for pp in plots_y1: ppp.append(" %s using %d:%d title '← %s(%s)' with lines"%(dataFile,vars.index(p)+1,vars.index(pp[0])+1,_xlateLabel(pp[0]),_xlateLabel(p),))
+		for pp in plots_y2: ppp.append(" %s using %d:%d title '%s(%s) →' with lines axes x1y2"%(dataFile,vars.index(p)+1,vars.index(pp[0])+1,_xlateLabel(pp[0]),_xlateLabel(p),))
 		fPlot.write("plot "+",".join(ppp)+"\n")
 		i+=1
 	fPlot.close()