← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 2705: 1. Revert some "cleanups" in Cell (LOL, Bruno, we are overwriting each other's work again :-))

 

------------------------------------------------------------
revno: 2705
committer: Václav Šmilauer <eu@xxxxxxxx>
branch nick: yade
timestamp: Mon 2011-01-31 20:09:24 +0100
message:
  1. Revert some "cleanups" in Cell (LOL, Bruno, we are overwriting each other's work again :-))
  2. Add some regression tests of PBC
  3. Make plot.addData aceept vectors and matrices, creating columns for individual components
  4. Make compilation of SpherePadder only optional (feature sphere-padder)
modified:
  CMakeLists.txt
  SConstruct
  core/Cell.hpp
  py/SConscript
  py/pack/pack.py
  py/plot.py
  py/tests/core.py
  py/tests/pbc.py
  py/tests/wrapper.py
  py/wrapper/yadeWrapper.cpp


--
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 'CMakeLists.txt'
--- CMakeLists.txt	2010-11-24 22:42:15 +0000
+++ CMakeLists.txt	2011-01-31 19:09:24 +0000
@@ -131,10 +131,10 @@
 #target_link_libraries(pkg core)
 SET(SRC_PYMODULES py/WeightedAverage2d.cpp;py/_eudoxos.cpp;py/log.cpp;py/_utils.cpp;py/wrapper/customConverters.cpp)
 
-SET(SRC_PACK ${CMAKE_SOURCE_DIR}/py/pack/_packPredicates.cpp;${CMAKE_SOURCE_DIR}/py/pack/_packObb.cpp;${CMAKE_SOURCE_DIR}/py/pack/_packSpheres.cpp;${CMAKE_SOURCE_DIR}/py/pack/_packSpherePadder.cpp;${CMAKE_SOURCE_DIR}/py/pack/SpherePadder/SpherePadder.cpp;${CMAKE_SOURCE_DIR}/py/pack/SpherePadder/TetraMesh.cpp;${CMAKE_SOURCE_DIR}/py/pack/SpherePadder/CellPartition.cpp)
-IF(${CGAL_FOUND})
-	SET(SRC_PACK ${SRC_PACK};${CMAKE_SOURCE_DIR}/py/pack/SpherePadder/SpherePackingTriangulation.cpp)
-ENDIF()
+SET(SRC_PACK ${CMAKE_SOURCE_DIR}/py/pack/_packPredicates.cpp;${CMAKE_SOURCE_DIR}/py/pack/_packObb.cpp;${CMAKE_SOURCE_DIR}/py/pack/_packSpheres.cpp) # ;${CMAKE_SOURCE_DIR}/py/pack/_packSpherePadder.cpp;${CMAKE_SOURCE_DIR}/py/pack/SpherePadder/SpherePadder.cpp;${CMAKE_SOURCE_DIR}/py/pack/SpherePadder/TetraMesh.cpp;${CMAKE_SOURCE_DIR}/py/pack/SpherePadder/CellPartition.cpp
+#IF(${CGAL_FOUND})
+#	SET(SRC_PACK ${SRC_PACK};${CMAKE_SOURCE_DIR}/py/pack/SpherePadder/SpherePackingTriangulation.cpp)
+#ENDIF()
 
 COMBINE_SOURCES(${CMAKE_BINARY_DIR}/pyPack "${SRC_PACK}" 100)
 SET(SRC_PACK_COMBINED "${CMAKE_BINARY_DIR}/pyPack.0.cpp")
@@ -172,7 +172,7 @@
 ## add_library(pyEigen STATIC py/mathWrap/miniEigen.cpp)
 
 
-SET(PY_COMPILED_MODULES mathWrap;gts/_gts;yade/boot;yade/log;yade/wrapper;yade/_customConverters;yade/_eudoxos;yade/_packPredicates;yade/_packSpheres;yade/_packSpherePadder;yade/_packObb;yade/_utils;yade/WeightedAverage2d)
+SET(PY_COMPILED_MODULES mathWrap;gts/_gts;yade/boot;yade/log;yade/wrapper;yade/_customConverters;yade/_eudoxos;yade/_packPredicates;yade/_packSpheres;yade/_packObb;yade/_utils;yade/WeightedAverage2d) # ;yade/_packSpherePadder
 IF(${QT4_FOUND})
 	SET(PY_COMPILED_MODULES ${PY_COMPILED_MODULES};yade/qt/_GLViewer)
 ENDIF()

=== modified file 'SConstruct'
--- SConstruct	2011-01-29 23:02:30 +0000
+++ SConstruct	2011-01-31 19:09:24 +0000
@@ -92,7 +92,7 @@
 	BoolVariable('gprof','Enable profiling information for gprof',0),
 	('optimize','Turn on optimizations (-1, 0 or 1); negative value sets optimization based on debugging: not optimize with debugging and vice versa.',-1,None,int),
 	EnumVariable('PGO','Whether to "gen"erate or "use" Profile-Guided Optimization','',['','gen','use'],{'no':'','0':'','false':''},1),
-	ListVariable('features','Optional features that are turned on','log4cxx,opengl,gts,openmp,vtk,qt4',names=['opengl','log4cxx','cgal','openmp','gts','vtk','gl2ps','qt4','never_use_this_one','subdomains']),
+	ListVariable('features','Optional features that are turned on','log4cxx,opengl,gts,openmp,vtk,qt4',names=['opengl','log4cxx','cgal','openmp','gts','vtk','gl2ps','qt4','sphere-padder','never_use_this_one','subdomains']),
 	('jobs','Number of jobs to run at the same time (same as -j, but saved)',2,None,int),
 	#('extraModules', 'Extra directories with their own SConscript files (must be in-tree) (whitespace separated)',None,None,Split),
 	('buildPrefix','Where to create build-[version][variant] directory for intermediary files','..'),

=== modified file 'core/Cell.hpp'
--- core/Cell.hpp	2011-01-31 16:01:57 +0000
+++ core/Cell.hpp	2011-01-31 19:09:24 +0000
@@ -7,7 +7,7 @@
 * Matrix3r *trsf* is "deformation gradient tensor" F (http://en.wikipedia.org/wiki/Finite_strain_theory) 
 * Matrix3r *velGrad* is "velocity gradient tensor" (http://www.cs.otago.ac.nz/postgrads/alexis/FluidMech/node7.html)
 
-The transformation is splitted between "normal" part and "rotation/shear" part for contact detection algorithms. The shearPt, unshearPt, getShearTrsf etc functions refer to both shear and rotation. This decomposition is frame-dependant and does not correspond to the rotation/stretch decomposition of mechanics (with stretch further decomposed into isotropic and deviatoric). Therefore, using the shearPt family in equations of mechanics is not recommended.
+The transformation is split between "normal" part and "rotation/shear" part for contact detection algorithms. The shearPt, unshearPt, getShearTrsf etc functions refer to both shear and rotation. This decomposition is frame-dependant and does not correspond to the rotation/stretch decomposition of mechanics (with stretch further decomposed into isotropic and deviatoric). Therefore, using the shearPt family in equations of mechanics is not recommended.
 
 */
 
@@ -16,14 +16,10 @@
 #include<yade/lib/serialization/Serializable.hpp>
 #include<yade/lib/base/Math.hpp>
 
-#define CELL_BACKW_COMPAT
-
 class Cell: public Serializable{
 	public:
-	//! Get current size
+	//! Get current size (refSize × normal strain)
 	const Vector3r& getSize() const { return _size; }
-	
-	void setSize(const Vector3r& s){for (int k=0;k<3;k++) hSize.col(k)*=s[k]/hSize.col(k).norm(); refHSize=hSize;  postLoad(*this);}
 	//! Return copy of the current size (used only by the python wrapper)
 	Vector3r getSize_copy() const { return _size; }
 	//! return vector of consines of skew angle in yz, xz, xy planes between respective transformed base vectors
@@ -93,22 +89,28 @@
 	Vector3r intrShiftVel(const Vector3i& cellDist) const { if(homoDeform==HOMO_VEL || homoDeform==HOMO_VEL_2ND) return velGrad*hSize*cellDist.cast<Real>(); return Vector3r::Zero(); }
 	// return body velocity while taking away mean field velocity (coming from velGrad) if the mean field velocity is applied on velocity
 	Vector3r bodyFluctuationVel(const Vector3r& pos, const Vector3r& vel) const { if(homoDeform==HOMO_VEL || homoDeform==HOMO_VEL_2ND) return (vel-velGrad*pos); return vel; }
+
 	// get/set mechanically undeformed shape; setting resets trsf to identity
 	Matrix3r getHSize() const { return hSize; }
 	void setHSize(const Matrix3r& m){ hSize=refHSize=m; trsf=Matrix3r::Identity(); postLoad(*this); }
 	// set current transformation; has no influence on current configuration (hSize); sets display refHSize as side-effect
 	Matrix3r getTrsf() const { return trsf; }
-	void setTrsf(const Matrix3r& m){ trsf=m; postLoad(*this); }
-#ifdef CELL_BACKW_COMPAT
-	Vector3r getRefSize() const { Matrix3r h=_invTrsf*hSize; return Vector3r(h.col(0).norm(),h.col(1).norm(),h.col(2).norm()); }
+	void setTrsf(const Matrix3r& m){ refHSize=hSize; trsf=m; postLoad(*this); }
+	// get undeformed shape
+	Matrix3r getHSize0() const { return _invTrsf*hSize; }
+	// edge lengths of the undeformed shape
+	Vector3r getRefSize() const { Matrix3r h=getHSize0(); return Vector3r(h.col(0).norm(),h.col(1).norm(),h.col(2).norm()); }
 	// temporary, will be removed in favor of more descriptive setBox(...)
 	void setRefSize(const Vector3r& s){
 		// if refSize is set to the current size and the cell is a box (used in older scripts), say it is not necessary
 		if(s==_size && hSize==hSize.diagonal().asDiagonal()){ LOG_WARN("Setting O.cell.refSize=O.cell.size is useless, O.trsf=Matrix3.Identity is enough now."); }
-		else {LOG_WARN("Setting Cell.refSize is deprecated, use O.cell.size=... instead.");}
-		setSize(s); postLoad(*this);
-	}
-#endif
+		else {LOG_WARN("Setting Cell.refSize is deprecated, use Cell.setBox(...) instead.");}
+		setBox(s); postLoad(*this);
+	} 
+	// set box shape of the cell
+	void setBox(const Vector3r& size){ setHSize(size.asDiagonal()); postLoad(*this); }
+	void setBox3(const Real& s0, const Real& s1, const Real& s2){ setBox(Vector3r(s0,s1,s2)); }
+
 	// return current cell volume
 	Real getVolume() const {return hSize.determinant();}
 	void postLoad(Cell&){ integrateAndUpdate(0); }
@@ -121,7 +123,7 @@
 	YADE_CLASS_BASE_DOC_ATTRS_DEPREC_INIT_CTOR_PY(Cell,Serializable,"Parameters of periodic boundary conditions. Only applies if O.isPeriodic==True.",
 		/* overridden below to be modified by getters/setters because of intended side-effects */
 		((Matrix3r,trsf,Matrix3r::Identity(),,"[overridden]")) //"Current transformation matrix of the cell, which defines how far is the current cell geometry (:yref:`hSize<Cell.hSize>`) from the reference configuration. Changing trsf will not change :yref:`hSize<Cell.hSize>`, it serves only as accumulator for transformations applied via :yref:`velGrad<Cell.velGrad>`."))
-		((Matrix3r,refHSize,Matrix3r::Identity(),,"Reference cell configuration, only used with :yref:`OpenGLRenderer.dispScale`. Updated automatically when :yref:`hSize<Cell.hSize>` or :yref:`hSize<Cell.size>` are assigned directly; also modified by :yref:`yade.utils.setRefSe3` (called e.g. by the :gui:`Reference` button in the UI)."))
+		((Matrix3r,refHSize,Matrix3r::Identity(),,"Reference cell configuration, only used with :yref:`OpenGLRenderer.dispScale`. Updated automatically when :yref:`hSize<Cell.hSize>` or :yref:`trsf<Cell.trsf>` is assigned directly; also modified by :yref:`yade.utils.setRefSe3` (called e.g. by the :gui:`Reference` button in the UI)."))
 		((Matrix3r,hSize,Matrix3r::Identity(),,"[overridden below]"))
 		/* normal attributes */
 		((Matrix3r,velGrad,Matrix3r::Zero(),,"Velocity gradient of the transformation; used in :yref:`NewtonIntegrator`. Values of :yref:`velGrad<Cell.velGrad>` accumulate in :yref:`trsf<Cell.trsf>` at every step."))
@@ -131,15 +133,17 @@
 		/*init*/ ,
 		/*ctor*/ _invTrsf=Matrix3r::Identity(); integrateAndUpdate(0),
 		/*py*/
-#ifdef CELL_BACKW_COMPAT
-		// for backward compat only. Don't use refSize in new scripts or new code. 
-		.add_property("refSize",&Cell::getRefSize,&Cell::setRefSize,"Reference size of the cell (lengths of initial cell vectors, i.e. column norms of :yref:`hSize<Cell.hSize>`).\n\n.. note:: Modifying this value is deprecated, use :yref:`size<Cell.size>` instead.\n\n")
-#endif
-		// useful properties
+		// override some attributes above
 		.add_property("hSize",&Cell::getHSize,&Cell::setHSize,"Base cell vectors (columns of the matrix), updated at every step from :yref:`velGrad<Cell.velGrad>` (:yref:`trsf<Cell.trsf>` accumulates applied :yref:`velGrad<Cell.velGrad>` transformations). Setting *hSize* directly results in :yref:`trsf<Cell.trsf>` being set to identity.")
+		.add_property("refSize",&Cell::getRefSize,&Cell::setRefSize,"Reference size of the cell (lengths of initial cell vectors, i.e. column norms of :yref:`hSize<Cell.hSize>`).\n\n.. note:: Modifying this value is deprecated, use :yref:`setBox<Cell.setBox>` instead.\n\n")
 		.add_property("trsf",&Cell::getTrsf,&Cell::setTrsf,"Current transformation matrix of the cell with regards to the initial configuration.")
-		.add_property("size",&Cell::getSize_copy,&Cell::setSize,"Current size of the cell, i.e. lengths of the 3 cell lateral vectors contained in :yref:`Cell.hSize` columns. Updated automatically at every step.")
+		// useful properties
+		.add_property("hSize0",&Cell::getHSize0,"Value of untransformed hSize, with respect to current :yref:`trsf<Cell.trsf>` (computed as :yref:`trsf<Cell.trsf>`⁻¹ × :yref:`hSize<Cell.hSize>`.")
+		.def_readonly("size",&Cell::getSize_copy,"Current size of the cell, i.e. lengths of the 3 cell lateral vectors contained in :yref:`Cell.hSize` columns. Updated automatically at every step.")
 		.add_property("volume",&Cell::getVolume,"Current volume of the cell.")
+		// functions
+		.def("setBox",&Cell::setBox,"Set :yref:`Cell` shape to be rectangular, with dimensions along axes specified by given argument. Shorthand for assigning diagonal matrix with respective entries to :yref:`hSize<Cell.hSize>`.")
+		.def("setBox",&Cell::setBox3,"Set :yref:`Cell` shape to be rectangular, with dimensions along $x$, $y$, $z$ specified by arguments. Shorthand for assigning diagonal matrix with the respective entries to :yref:`hSize<Cell.hSize>`.")
 		// debugging only
 		.def("wrap",&Cell::wrapShearedPt_py,"Transform an arbitrary point into a point in the reference cell")
 		.def("unshearPt",&Cell::unshearPt,"Apply inverse shear on the point (removes skew+rot of the cell)")

=== modified file 'py/SConscript'
--- py/SConscript	2011-01-12 16:22:18 +0000
+++ py/SConscript	2011-01-31 19:09:24 +0000
@@ -16,10 +16,11 @@
 		# link to the symlink to the python module (created in lib/SConstruct; see explanation there)
 		LIBS=env['LIBS']+(['_gts__python-module'] if 'YADE_GTS' in env['CPPDEFINES'] else []),
 		),
-	env.SharedLibrary('_packSpherePadder',env.Combine('packSpherePadder.cpp',['pack/_packSpherePadder.cpp','pack/SpherePadder/SpherePadder.cpp','pack/SpherePadder/TetraMesh.cpp','pack/SpherePadder/CellPartition.cpp']+(['pack/SpherePadder/SpherePackingTriangulation.cpp'] if 'cgal' in env['features'] else [])),SHLIBPREFIX='',LIBS=env['LIBS']+linkPlugins(['SpherePack'])),
 	env.SharedLibrary('_packSpheres',['pack/_packSpheres.cpp'],SHLIBPREFIX='',LIBS=env['LIBS']+[
 		linkPlugins(['Shop','SpherePack']),
-		]),
+		])
+	# include SpherePadder only optionally
+	]+([env.SharedLibrary('_packSpherePadder',env.Combine('packSpherePadder.cpp',['pack/_packSpherePadder.cpp','pack/SpherePadder/SpherePadder.cpp','pack/SpherePadder/TetraMesh.cpp','pack/SpherePadder/CellPartition.cpp']+(['pack/SpherePadder/SpherePackingTriangulation.cpp'] if 'cgal' in env['features'] else [])),SHLIBPREFIX='',LIBS=env['LIBS']+linkPlugins(['SpherePack'])) if 'sphere-padder' in env['features'] else []])+[
 	env.SharedLibrary('_packObb',['pack/_packObb.cpp'],SHLIBPREFIX=''),
 	env.AlwaysBuild(env.ScanReplace('__init__.py.in')),
 	env.AlwaysBuild(env.ScanReplace('config.py.in')),

=== modified file 'py/pack/pack.py'
--- py/pack/pack.py	2011-01-30 15:43:18 +0000
+++ py/pack/pack.py	2011-01-31 19:09:24 +0000
@@ -45,7 +45,9 @@
 # import SpherePack
 from _packSpheres import *
 from _packObb import *
-from _packSpherePadder import *
+try:
+	from _packSpherePadder import *
+except ImportError: pass
 
 ##
 # extend _packSphere.SpherePack c++ class by this method

=== modified file 'py/plot.py'
--- py/plot.py	2011-01-29 22:47:18 +0000
+++ py/plot.py	2011-01-31 19:09:24 +0000
@@ -6,7 +6,7 @@
 """
 
 ## all exported names
-__all__=['data','plots','labels','live','liveInterval','autozoom','plot','reset','resetData','splitData','reverse','addData','saveGnuplot','saveDataTxt','savePlotSequence']
+__all__=['data','plots','labels','live','liveInterval','autozoom','plot','reset','resetData','splitData','reverseData','addData','saveGnuplot','saveDataTxt','savePlotSequence']
 
 # multi-threaded support for Tk
 # safe to import even if Tk will not be used
@@ -35,6 +35,8 @@
 import yade.runtime
 if not yade.runtime.hasDisplay: matplotlib.use('Agg')
 
+from miniEigen import *
+
 #matplotlib.use('TkAgg')
 #matplotlib.use('GTKAgg')
 ##matplotlib.use('QtAgg')
@@ -67,9 +69,10 @@
 "Linewidth (in points) to make *x* and *y* axes better visible; not activated if non-positive."
 current=-1
 "Point that is being tracked with a scatter point. -1 is for the last point, set to *nan* to disable."
-#take3dSnapshots=False
-#"If true, take snapshot of the 3d view using :yref:`yade.qt.SnapshotEngine` every time :yref:`yade.plot.addData` is called"
-#snapshotEngine=None
+
+componentSeparator='_'
+componentSuffixes={Vector2:{0:'x',1:'y'},Vector3:{0:'x',1:'y',2:'z'},Matrix3:{(0,0):'xx',(1,1):'yy',(2,2):'zz',(0,1):'xy',(0,2):'xz',(1,2):'yz',(1,0):'yz',(2,0):'zx',(2,1):'zy'}}
+# if a type with entry in componentSuffixes is given in addData, columns for individual components are synthesized using indices and suffixes given for each type, e.g. foo=Vector3r(1,2,3) will result in columns foox=1,fooy=2,fooz=3
 
 def reset():
 	"Reset all plot-related variables (data, plots, labels)"
@@ -106,10 +109,36 @@
 	"""Add data from arguments name1=value1,name2=value2 to yade.plot.data.
 	(the old {'name1':value1,'name2':value2} is deprecated, but still supported)
 
-	New data will be left-padded with nan's, unspecified data will be nan.
+	New data will be padded with nan's, unspecified data will be nan (nan's don't appear in graphs).
 	This way, equal length of all data is assured so that they can be plotted one against any other.
 
-	Nan's don't appear in graphs."""
+	>>> from yade import plot
+	>>> from pprint import pprint
+	>>> plot.resetData()
+	>>> plot.addData(a=1)
+	>>> plot.addData(b=2)
+	>>> plot.addData(a=3,b=4)
+	>>> pprint(plot.data)
+	{'a': [1, nan, 3], 'b': [nan, 2, 4]}
+
+	Some sequence types can be given to addData; they will be saved in synthesized columns for individual components.
+
+	>>> plot.resetData()
+	>>> plot.addData(c=Vector3(5,6,7),d=Matrix3(8,9,10, 11,12,13, 14,15,16))
+	>>> pprint(plot.data)
+ 	{'c_x': [5.0],
+	 'c_y': [6.0],
+	 'c_z': [7.0],
+	 'd_xx': [8.0],
+	 'd_xy': [9.0],
+	 'd_xz': [10.0],
+	 'd_yy': [12.0],
+	 'd_yz': [11.0],
+	 'd_zx': [14.0],
+	 'd_zy': [15.0],
+	 'd_zz': [16.0]}
+
+	"""
 	import numpy
 	if len(data)>0: numSamples=len(data[data.keys()[0]])
 	else: numSamples=0
@@ -117,6 +146,16 @@
 	if len(imgData)>0 and numSamples==0: numSamples=max(numSamples,len(imgData[imgData.keys()[0]]))
 	d=(d_in[0] if len(d_in)>0 else {})
 	d.update(**kw)
+	# handle types composed of multiple values (vectors, matrices)
+	dNames=d.keys()[:] # make copy, since dict cannot change size if iterated over directly
+	for name in dNames:
+		if type(d[name]) in componentSuffixes:
+			val=d[name]
+			suffixes=componentSuffixes[type(d[name])]
+			for ix in suffixes: d[name+componentSeparator+suffixes[ix]]=d[name][ix]
+			del d[name]
+		elif hasattr(d[name],'__len__'):
+			raise ValueError('plot.addData given unhandled sequence type (is a '+type(d[name]).__name__+', must be number or '+'/'.join([k.__name__ for k in componentSuffixes])+')')
 	for name in d:
 		if not name in data.keys(): data[name]=[]
 	for name in data:
@@ -219,6 +258,7 @@
 			# fake (empty) image if no data yet
 			if len(imgData[pStrip])==0 or imgData[pStrip][-1]==None: img=Image.new('RGBA',(1,1),(0,0,0,0))
 			else: img=Image.open(imgData[pStrip][-1])
+
 			img=pylab.imshow(img,origin='lower')
 			currLineRefs.append(LineRef(img,None,imgData[pStrip],None,pStrip))
 			pylab.gca().set_axis_off()
@@ -406,6 +446,7 @@
 	You can use 
 	
 		>>> from yade import plot
+		>>> plot.resetData()
 		>>> plot.plots={'foo':('bar',)}
 		>>> plot.plot(noShow=True).savefig('someFile.pdf')
 		>>> import os

=== modified file 'py/tests/core.py'
--- py/tests/core.py	2011-01-20 14:55:15 +0000
+++ py/tests/core.py	2011-01-31 19:09:24 +0000
@@ -147,7 +147,7 @@
 		self.assert_(O.bodies[0].mat.young==O.bodies[1].mat.young)
 	def testSharedAfterReload(self):
 		"Material: shared_ptr's are preserved when saving/loading"
-		O.saveTmp(); O.loadTmp()
+		O.saveTmp(quiet=True); O.loadTmp(quiet=True)
 		O.bodies[0].mat.young=9087438484
 		self.assert_(O.bodies[0].mat.young==O.bodies[1].mat.young)
 	def testLen(self):

=== modified file 'py/tests/pbc.py'
--- py/tests/pbc.py	2011-01-29 22:47:18 +0000
+++ py/tests/pbc.py	2011-01-31 19:09:24 +0000
@@ -18,7 +18,7 @@
 	# prefix test names with PBC: 
 	def setUp(self):
 		O.reset(); O.periodic=True;
-		O.cell.refSize=(2.5,2.5,3)
+		O.cell.setBox(2.5,2.5,3)
 		self.cellDist=Vector3i(0,0,10) # how many cells away we go
 		self.relDist=Vector3(0,.999999999999999999,0) # rel position of the 2nd ball within the cell
 		self.initVel=Vector3(0,0,5)
@@ -27,13 +27,35 @@
 		O.bodies.append(utils.sphere(self.initPos,.5))
 		#print O.bodies[1].state.pos
 		O.bodies[1].state.vel=self.initVel
-		O.engines=[NewtonIntegrator()]
+		O.engines=[NewtonIntegrator(warnNoForceReset=False)]
 		O.cell.velGrad=Matrix3(0,0,0, 0,0,0, 0,0,-1)
 		O.cell.homoDeform=3
 		O.dt=0 # do not change positions with dt=0 in NewtonIntegrator, but still update velocities from velGrad
-	def testRefSize(self):
-		"PBC: hSize reflects changes of refSize"
-		O.cell.refSize=(2.55,11,45)
+	def testVelGrad(self):
+		'PBC: velGrad changes hSize but not hSize0, accumulates in trsf'
+		O.dt=1e-3
+		hSize,trsf=O.cell.hSize,Matrix3.Identity
+		hSize0=hSize
+		for i in range(0,10):
+			O.step(); hSize+=O.dt*O.cell.velGrad*hSize; trsf+=O.dt*O.cell.velGrad*trsf
+		for i in range(0,len(O.cell.hSize)):
+			self.assertAlmostEqual(hSize[i],O.cell.hSize[i])
+			self.assertAlmostEqual(trsf[i],O.cell.trsf[i])
+			# ?? should work
+			#self.assertAlmostEqual(hSize0[i],O.cell.hSize0[i])
+	def testTrsfChange(self):
+		'PBC: chaing trsf changes hSize0, but does not modify hSize'
+		O.dt=1e-2
+		O.step()
+		O.cell.trsf=Matrix3.Identity
+		for i in range(0,len(O.cell.hSize)):
+			self.assertAlmostEqual(O.cell.hSize0[i],O.cell.hSize[i])
+	def testDegenerate(self):
+		"PBC: degenerate cell raises exception"
+		self.assertRaises(RuntimeError,lambda: setattr(O.cell,'hSize',Matrix3(1,0,0, 0,0,0, 0,0,1)))
+	def testSetBox(self):
+		"PBC: setBox modifies hSize correctly"
+		O.cell.setBox(2.55,11,45)
 		self.assert_(O.cell.hSize==Matrix3(2.55,0,0, 0,11,0, 0,0,45));
 	def testHomotheticResizeVel(self):
 		"PBC: homothetic cell deformation adjusts particle velocity (homoDeform==3)"

=== modified file 'py/tests/wrapper.py'
--- py/tests/wrapper.py	2011-01-20 14:55:15 +0000
+++ py/tests/wrapper.py	2011-01-31 19:09:24 +0000
@@ -83,9 +83,9 @@
 		O.bodies.append(utils.sphere((0,0,0),1))
 		O.engines=[InsertionSortCollider([Bo1_Sphere_Aabb()]),NewtonIntegrator()]
 		O.step()
-		O.saveTmp()
+		O.saveTmp(quiet=True)
 		mn0=Vector3(O.bodies[0].bound.min)
-		O.reload()
+		O.reload(quiet=True)
 		mn1=Vector3(O.bodies[0].bound.min)
 		# check that the minimum is not saved
 		self.assert_(not isnan(mn0[0]))

=== modified file 'py/wrapper/yadeWrapper.cpp'
--- py/wrapper/yadeWrapper.cpp	2011-01-09 16:34:50 +0000
+++ py/wrapper/yadeWrapper.cpp	2011-01-31 19:09:24 +0000
@@ -375,7 +375,7 @@
 		OMEGA.createSimulationLoop();
 		mapLabeledEntitiesToVariables();
 	}
-	void reload(){	load(OMEGA.sceneFile);}
+	void reload(bool quiet=false){	load(OMEGA.sceneFile,quiet);}
 	void saveTmp(string mark="", bool quiet=false){ save(":memory:"+mark,quiet);}
 	void loadTmp(string mark="", bool quiet=false){ load(":memory:"+mark,quiet);}
 	python::list lsTmp(){ python::list ret; typedef pair<std::string,string> strstr; FOREACH(const strstr& sim,OMEGA.memSavedSimulations){ string mark=sim.first; boost::algorithm::replace_first(mark,":memory:",""); ret.append(mark); } return ret; }
@@ -532,7 +532,7 @@
 		.add_property("dynDt",&pyOmega::dynDt_get,"Whether a :yref:`TimeStepper` is used for dynamic Δt control. See :yref:`dt<Omega.dt>` on how to enable/disable :yref:`TimeStepper`.")
 		.add_property("dynDtAvailable",&pyOmega::dynDtAvailable_get,"Whether a :yref:`TimeStepper` is amongst :yref:`O.engines<Omega.engines>`, activated or not.")
 		.def("load",&pyOmega::load,(py::arg("file"),py::arg("quiet")=false),"Load simulation from file.")
-		.def("reload",&pyOmega::reload,"Reload current simulation")
+		.def("reload",&pyOmega::reload,(py::arg("quiet")=false),"Reload current simulation")
 		.def("save",&pyOmega::save,(py::arg("file"),py::arg("quiet")=false),"Save current simulation to file (should be .xml or .xml.bz2)")
 		.def("loadTmp",&pyOmega::loadTmp,(py::arg("mark")="",py::arg("quiet")=false),"Load simulation previously stored in memory by saveTmp. *mark* optionally distinguishes multiple saved simulations")
 		.def("saveTmp",&pyOmega::saveTmp,(py::arg("mark")="",py::arg("quiet")=false),"Save simulation to memory (disappears at shutdown), can be loaded later with loadTmp. *mark* optionally distinguishes different memory-saved simulations.")