← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 2278: 1. Adjust debian-related packaging files

 

------------------------------------------------------------
revno: 2278
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Sun 2010-06-06 12:18:07 +0200
message:
  1. Adjust debian-related packaging files
  2. Remove NullGUI for good
  3. Remove non-DISPATCH_CACHE code (not used)
removed:
  core/NullGUI.cpp
  core/NullGUI.hpp
added:
  scripts/debian-packages
modified:
  SConstruct
  core/SConscript
  core/main/yade-multi.in
  debian/control-template
  debian/rules
  doc/sphinx/yadeSphinx.py
  pkg/common/Engine/Dispatcher/InteractionDispatchers.cpp
  py/system.py
  scripts/debian-prep


--
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-05-24 21:42:47 +0000
+++ SConstruct	2010-06-06 10:18:07 +0000
@@ -236,9 +236,10 @@
 		print cmd; os.system(cmd)
 		sys.argv.remove('tags')
 	if 'doc' in sys.argv:
-		cmd="cd doc; doxygen Doxyfile"
-		print cmd; os.system(cmd)
-		sys.argv.remove('doc')
+		raise RuntimeError("'doc' argument not supported by scons now")
+	#	cmd="cd doc; doxygen Doxyfile"
+	#	print cmd; os.system(cmd)
+	#	sys.argv.remove('doc')
 	# still something on the command line? Ignore, but warn about that
 	if len(sys.argv)>1: print "!!! WARNING: Shortcuts (clean,tags,doc) cannot be mixed with regular targets or options; ignoring:\n"+''.join(["!!!\t"+a+"\n" for a in sys.argv[1:]])
 	# bail out

=== removed file 'core/NullGUI.cpp'
--- core/NullGUI.cpp	2010-05-13 20:19:38 +0000
+++ core/NullGUI.cpp	1970-01-01 00:00:00 +0000
@@ -1,243 +0,0 @@
-/*************************************************************************
-*  Copyright (C) 2004 by Janek Kozicki                                   *
-*  cosurgi@xxxxxxxxxx                                                    *
-*                                                                        *
-*  This program is free software; it is licensed under the terms of the  *
-*  GNU General Public License v2 or later. See file LICENSE for details. *
-*************************************************************************/
-
-#include "NullGUI.hpp"
-#include "Scene.hpp"
-#include "FileGenerator.hpp"
-#include <iostream>
-#include <boost/filesystem/convenience.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
-
-using namespace std;
-
-NullGUI::NullGUI ()
-{
-	interval = 100;
-	progress = false;
-	snapshotInterval = -1;
-	snapshotName = "";
-	maxIteration = 0;
-	binary = 0;
-	filegen = "";
-	file = "";
-}
-
-
-NullGUI::~NullGUI()
-{
-
-}
-
-
-void NullGUI::help()
-{
-	cout <<
-"\n" << Omega::instance().yadeVersionName << " NullGUI frontend.\n\
-\n\
-	-H		- print this help.\n\
-\n\
-    user feedback:\n\
-	-v number	- specify iteration INTERVAL in which other tasks are\n\
-			  performed, default is set to 100.\n\
-	-p		- print progress information every INTERVAL iteration\n\
-			  so you see that calculations are going on.\n\
-\n\
-    input:\n\
-	-f name		- specify filename to load, or filegenerator configuration file\n\
-			  (if a filegenerator then it must be a last parameter\n\
-			  and multiple filegenerators are allowed)\n\
-\n\
-    output:\n\
-	-s number	- if specified, a snapshot is saved every 'number'\n\
-			  INTERVALs. Eg. if INTERVAL is 100, and 'number' is 5,\n\
-			  you will have a snpashot every 500th iteration.\n\
-	-S name		- specify base filename of snapshot. Defaults to input\n\
-			  filename. Filename has appended iteration number.\n\
-			  Or specify FileGenerator output file if generating a file.\n\
-			  (without extension, use -b to get binary output)\n\
-        -Q name		- do not calculate, just save what is loaded and exit\n\
-			  (for doing data conversions)\n\
-	-F name		- FileGenerator name, must be specified with -f that specifies\n\
-			  the accompanying configuration file (used for file generation)\n\
-			  and with -S that specifies the output file to save\n\
-\n\
-    options:\n\
-	-m number	- specify maximum number of iterations\n\
-			  ( 0 = unlimited, tested every INTERVAL iteration).\n\
-	-t number	- set time step in seconds, default is 0.01 (FIXME - inside .xml)\n\
-	-b number	- save in binary .yade format instead of .xml\n\
-\n";
-//      -g number       - set gravity, default is 9.81 (FIXME - inside .xml)\n
-}
-
-std::string quickSave("");
-
-int NullGUI::run(int argc, char* argv[])
-{
-
-	int ch;
-	std::vector<std::string> inputFiles;
-	for(int i=argc-1 ; std::string(argv[i])[0]!='-' && i>1 ; --i )
-		inputFiles.insert(inputFiles.begin(),argv[i]);
-	while( ( ch = getopt(argc,argv,"Hf:s:S:v:pm:t:g:bQ:F:") ) != -1)
-		switch(ch)
-		{
-			case 'H'        : help();                                               return 1;
-			case 'v'	: interval = lexical_cast<int>(optarg);			break;
-			case 'p'	: progress = true;					break;
-			case 'F'	: filegen = optarg;					break;
-			case 'f'	: file = optarg;					break;
-			case 's'        : snapshotInterval = lexical_cast<int>(optarg);		break;
-			case 'S'        : snapshotName = optarg;				break;
-			case 'Q'        : quickSave = optarg;					break;
-			case 'm'        : maxIteration = lexical_cast<long int>(optarg);	break;
-			case 'b'        : binary = true;					break;
-			case 't'        : Omega::instance().getScene()->dt=(lexical_cast<Real>(optarg));			break;
-//			case 'g'	: Omega::instance().setGravity
-//						(Vector3r(0,-lexical_cast<Real>(optarg),0));	break;
-			default		:help(); 						return 1;
-		}
-	if(filegen.empty()) // calculations
-	{
-		Omega::instance().setSimulationFileName(file);
-		if(snapshotName.empty() ) snapshotName = file;
-		if(Omega::instance().getSimulationFileName() == "") 
-			help(), exit(0);
-		return loop();
-	} 
-	else // FileGenerator
-	{
-		for(size_t i=0; i<inputFiles.size() ; ++i)
-		{
-			std::cerr << "filegenerator: \"" << inputFiles[i] << "\"";
-			file=inputFiles[i];
-			gen();
-		}
-		return 0;
-	}
-
-	assert(false); // never reach this place
-}
-
-
-int NullGUI::loop()
-{
-	try
-	{
-		Omega::instance().loadSimulation();
-	}
-	catch(SerializableError& e)
-	{
-		std::cerr << file << " cannot be loaded: " << e.what() << "\n";
-		exit(0);
-	}
-		
-	if(quickSave.size()!=0)
-		std::cerr << "saving "<< quickSave << "\n", Omega::instance().saveSimulation(quickSave), exit(1);
-
-	cerr << "Starting computation of file: " << Omega::instance().getSimulationFileName() << endl;
-
-	if( maxIteration == 0)
-		cerr << "No maxiter specified, computations will run forever, to set it, use flag -m\n";
-	else
-		cerr << "Computing " << maxIteration << " iterations\n";
-
-	cerr << "Using timestep: " << Omega::instance().getScene()->dt << endl;
-
-	filesystem::path p(snapshotName);
-	if(filesystem::extension(p)==".gz")
-	{
-		std::cerr << "Error: .gz is no longer supported, use .bz2 instead.";
-		exit(1);
-	}
-	if(filesystem::extension(p)==".bz2")
-		p = filesystem::basename(p); // get rid of .bz2
-	snapshotName = filesystem::basename(p); // get rid of .xml
-	if( snapshotInterval != -1 )
-		cerr 	<< "Saving snapshot every " << snapshotInterval*interval << " iterations, \n"
-			<< "to filename: " << snapshotName << "_[0-9]" << endl;
-
-	long int intervals = 0;
-	boost::posix_time::ptime start = boost::posix_time::second_clock::local_time();
-	while(1)
-	{
-		Omega::instance().getScene()->moveToNextTimeStep();
-
-		if(Omega::instance().getCurrentIteration() % interval == 0 )
-		{
-			++intervals;
-
-			// print progress...
-			if(progress)
-				cerr << "iteration: " << Omega::instance().getCurrentIteration() << endl;
-
-			// save snapshot
-			if( ( snapshotInterval != -1 ) && (intervals % snapshotInterval == 0) )
-			{
-				string fileName = "./" 
-					+ snapshotName 
-			//		+ "__dt_" + lexical_cast<string>(Omega::instance().getTimeStep())
-			//		+ "__it_" + lexical_cast<string>(Omega::instance().getCurrentIteration()) 
-					+ "_" + lexical_cast<string>(Omega::instance().getCurrentIteration()) 
-					+ (binary?".xml.bz2":".xml");
-				cerr << "saving snapshot: " << fileName << "   ...";
-				Omega::instance().saveSimulation(fileName);
-				cerr << " done.\n";
-			}
-		}
-
-		// finish computation
-		if( ( maxIteration !=0 ) &&  (Omega::instance().getCurrentIteration() >= maxIteration) )
-		{
-			cerr << "Calc finished at: " << Omega::instance().getCurrentIteration() << endl;
-			cerr << "Computation time: " << boost::posix_time::to_simple_string(boost::posix_time::time_duration(boost::posix_time::second_clock::local_time() - start)) << endl;
-			exit(0);
-		}
-	}
-}
-
-int NullGUI::gen()
-{
-	if(snapshotName.empty())
-		std::cerr << "please specufy output file name with -S\n"
-		"(if output file is specified inside generator config, then specify \"none\")\n", exit(0);
-	if(file.empty())
-		std::cerr << "please specify config file name with -f\n", exit(0);
-	shared_ptr<Factorable> tmpf;
-	try
-	{
-		tmpf = ClassFactory::instance().createShared(filegen);
-	}
-	catch(FactoryError& e)
-	{
-		std::cerr << filegen << " is not available: " << e.what() << "\n", exit(0);
-	}
-	shared_ptr<FileGenerator> f = dynamic_pointer_cast<FileGenerator>(tmpf);
-	if( f == 0 )
-		std::cerr << filegen << " is not a FileGenerator.\n", exit(0);
-	try
-	{
-		std::cerr << "loading FileGenerator configuration file: " << file << "\n";
-		IOFormatManager::loadFromFile("XMLFormatManager",file,"fileGenerator",f);
-	}
-	catch(SerializableError& e)
-	{
-		std::cerr << file << " cannot be loaded: " << e.what() << "\n", exit(0);
-	}
-	if(snapshotName=="none")
-		std::cerr << "filegenerator output name set to \"none\" - using default output name.\n";
-	else
-		f->setFileName(snapshotName + (binary?".xml.bz2":".xml"));
-	std::cerr	<< "calling FileGenerator: " << filegen 
-			<< ",\nwith config file: " << file 
-			<< ",\nto generate file: " << f->getFileName() << "\n\n";
-	f->setSerializationLibrary("XMLFormatManager");
-	std::cerr << "\n" << f->generateAndSave() << "\n";
-	return 0;
-};
-

=== removed file 'core/NullGUI.hpp'
--- core/NullGUI.hpp	2009-01-27 02:19:40 +0000
+++ core/NullGUI.hpp	1970-01-01 00:00:00 +0000
@@ -1,43 +0,0 @@
-/*************************************************************************
-*  Copyright (C) 2004 by Janek Kozicki                                   *
-*  cosurgi@xxxxxxxxxx                                                    *
-*                                                                        *
-*  This program is free software; it is licensed under the terms of the  *
-*  GNU General Public License v2 or later. See file LICENSE for details. *
-*************************************************************************/
-
-#pragma once
-
-// FIXME : there is a problem because I need to link with serialization when I include Factorable because Factorable use some Type described in serialization for the findClassInfo method
-#include "FrontEnd.hpp"
-
-/*! \brief
-	This GUI is commmand line interface for yade - just starts calculations and never ends
-	(unless, maxiter is given) and it requires a filename, also assumes -a flag.
-*/
-class NullGUI : public FrontEnd
-{
-	private :
-		int 		 interval
-				,snapshotInterval;
-
-		bool 		 progress;
-		bool 		 binary;
-		string		 snapshotName,filegen,file;
-		long int	 maxIteration;
-		
-		void help();
-		int loop();
-		int gen();
-
-	public :
-		NullGUI ();
-		virtual ~NullGUI ();
-		virtual int run(int argc, char *argv[]);
-	
-	REGISTER_CLASS_AND_BASE(NullGUI,FrontEnd);
-};
-
-REGISTER_FACTORABLE(NullGUI);
-
-

=== modified file 'core/SConscript'
--- core/SConscript	2010-05-08 14:53:54 +0000
+++ core/SConscript	2010-06-06 10:18:07 +0000
@@ -42,7 +42,6 @@
 			'Material.cpp',
 			'Scene.cpp',
 			'Dispatcher.cpp',
-			'NullGUI.cpp',
 			'Omega.cpp',
 			'Shape.cpp',
 			'SimulationFlow.cpp',

=== modified file 'core/main/yade-multi.in'
--- core/main/yade-multi.in	2010-04-13 21:09:57 +0000
+++ core/main/yade-multi.in	2010-06-06 10:18:07 +0000
@@ -160,7 +160,7 @@
 	return nCpu
 numCores=getNumCores()
 
-parser=optparse.OptionParser(usage='%prog [options] TABLE SIMULATION.py\n\n  %prog runs yade simulation multiple times with different parameters.\n  See http://yade.wikia.com/wiki/ScriptParametricStudy for details.')
+parser=optparse.OptionParser(usage='%prog [options] TABLE SIMULATION.py\n\n  %prog runs yade simulation multiple times with different parameters.\n  See https://yade-dem.org/sphinx/user.html#batch-queuing-and-execution-yade-multi for details.')
 parser.add_option('-j','--jobs',dest='maxJobs',type='int',help="Maximum number of simultaneous threads to run (default: number of cores, further limited by OMP_NUM_THREADS if set by the environment: %d)"%numCores,metavar='NUM',default=numCores)
 parser.add_option('--job-threads',dest='defaultThreads',type='int',help="Default number of threads for one job; can be overridden by per-job OMP_NUM_THREADS. Defaults to allocate all available cores (%d) for each job."%numCores,metavar='NUM',default=numCores)
 parser.add_option('--force-threads',action='store_true',dest='forceThreads')

=== modified file 'debian/control-template'
--- debian/control-template	2010-05-28 20:57:41 +0000
+++ debian/control-template	2010-06-06 10:18:07 +0000
@@ -2,7 +2,7 @@
 Section: x11
 Priority: optional
 Maintainer: Václav Šmilauer <eudoxos@xxxxxxxx>
-Build-Depends: debhelper (>= 5), scons, libqt3-mt-dev, qt3-dev-tools, freeglut3-dev, libboost-dev (>=1.34), libboost-date-time-dev (>=1.34), libboost-filesystem-dev (>=1.34), libboost-thread-dev (>=1.34), libboost-regex-dev (>=1.34), libboost-python-dev (>=1.34), libboost-iostreams-dev (>=1.34), libboost-program-options-dev, libboost-serialization-dev, liblog4cxx9-dev | liblog4cxx10-dev, docbook-to-man, ipython, libsqlite3-dev, libgts-dev, python-numpy, g++(>4.0), libvtk5-dev, libgl1-mesa-dev, gdb, ipython, python-matplotlib, python-tk, libeigen2-dev @', libqglviewer-qt3-dev' if DISTRIBUTION!='hardy' else ''@ @', binutils-gold' if DISTRIBUTION not in ('hardy','intrepid','jaunty','lenny') else ''@
+Build-Depends: debhelper (>= 5), scons, libqt3-mt-dev, qt3-dev-tools, freeglut3-dev, libboost-dev (>=1.34), libboost-date-time-dev (>=1.34), libboost-filesystem-dev (>=1.34), libboost-thread-dev (>=1.34), libboost-regex-dev (>=1.34), libboost-python-dev (>=1.34), libboost-iostreams-dev (>=1.34), libboost-program-options-dev, libboost-serialization-dev, liblog4cxx9-dev | liblog4cxx10-dev, docbook-to-man, ipython, libsqlite3-dev, libgts-dev, python-numpy, g++(>4.0), libvtk5-dev, libgl1-mesa-dev, gdb, ipython, python-matplotlib, python-tk, libeigen2-dev @', libqglviewer-qt3-dev' if DISTRIBUTION!='hardy' else ''@ @', binutils-gold' if DISTRIBUTION not in ('hardy','intrepid','jaunty','lenny') else ''@ @', texlive-latex-recommended, python-sphinx' if DISTRIBUTION not in ('hardy','intrepid','jaunty','lenny') else ''@
 Standards-Version: 3.7.2
 
 Package: yade@_VERSION@

=== modified file 'debian/rules'
--- debian/rules	2010-05-13 20:19:38 +0000
+++ debian/rules	2010-06-06 10:18:07 +0000
@@ -46,6 +46,8 @@
 	# scons clean
 	## remove builddirs and installation directories
 	rm -rf debian/build-* `find debian/ -name 'yade-*' -type d`
+	rm -rf doc/sphinx/_build
+	rm -rf tags
 	dh_clean 
 
 install: build
@@ -58,11 +60,16 @@
 	###   (a) use fakeroot-tcp instead of fakeroot
 	###   (b) use just 1 job
 	#debug build
-	NO_SCONS_GET_RECENT= scons profile=deb 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:/usr/include/eigen2
+	NO_SCONS_GET_RECENT= scons profile=deb buildPrefix=debian runtimePREFIX=/usr version=${VERSION} brief=0 chunkSize=1 jobs=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:/usr/include/eigen2
 	#optimized build
 	NO_SCONS_GET_RECENT= scons profile=deb PREFIX=debian/yade${_VERSION}/usr variant='' optimize=1 debug=0
 	#install platform-independent files (docs, scripts, examples)
-	NO_SCONS_GET_RECENT= scons profile=deb PREFIX=debian/yade${_VERSION}/usr debian/yade${_VERSION}/usr/share/doc/yade${_VERSION}-doc
+	#NO_SCONS_GET_RECENT= scons profile=deb PREFIX=debian/yade${_VERSION}/usr debian/yade${_VERSION}/usr/share/doc/yade${_VERSION}-doc
+	mkdir -p debian/yade${_VERSION}/usr/share/doc/yade${_VERSION}-doc
+	cp -r examples scripts debian/yade${_VERSION}/usr/share/doc/yade${_VERSION}-doc
+	# UGLY! generate sphinx docs only if python-sphinx is installed (distinguishes distributions which should build it or not as per debian/control-template build-deps)
+	if [ "`dpkg -l python-sphinx |grep -e '^ii'`" ]; then cd doc/sphinx; ../../scripts/yade-exec-wrapper debian/yade${_VERSION}/usr/bin/yade${_VERSION} yadeSphinx.py; cp -r _build/html  debian/yade${_VERSION}/usr/share/doc/yade${_VERSION}-doc/html; else echo "Not building HTML documentation, since the python-sphinx package is not installed"; fi
+
 
 check: install
 	dh_testdir

=== modified file 'doc/sphinx/yadeSphinx.py'
--- doc/sphinx/yadeSphinx.py	2010-05-28 20:57:41 +0000
+++ doc/sphinx/yadeSphinx.py	2010-06-06 10:18:07 +0000
@@ -188,6 +188,7 @@
 writer=None
 
 for w in ['latex','html']: #['html','latex']:
+	if 'nolatex' in sys.argv and w=='latex': continue # skip latex build if passed nolatex (used in debian packages)
 	writer=w
 	genWrapperRst()
 	# HACK: must rewrite sys.argv, since reference generator in conf.py determines if we output latex/html by inspecting it

=== modified file 'pkg/common/Engine/Dispatcher/InteractionDispatchers.cpp'
--- pkg/common/Engine/Dispatcher/InteractionDispatchers.cpp	2010-04-25 13:18:11 +0000
+++ pkg/common/Engine/Dispatcher/InteractionDispatchers.cpp	2010-06-06 10:18:07 +0000
@@ -22,8 +22,6 @@
 	#define IDISP_CHECKPOINT(cpt)
 #endif
 
-#define DISPATCH_CACHE
-
 void InteractionDispatchers::action(){
 	#ifdef IDISP_TIMING
 		timingDeltas->start();
@@ -63,111 +61,89 @@
 	#else
 		FOREACH(shared_ptr<Interaction> I, *scene->interactions){
 	#endif
-		#ifdef DISPATCH_CACHE
-			if(removeUnseenIntrs && !I->isReal() && I->iterLastSeen<scene->currentIteration) {
-				eraseAfterLoop(I->getId1(),I->getId2());
-				continue;
-			}
-
-			const shared_ptr<Body>& b1_=Body::byId(I->getId1(),scene);
-			const shared_ptr<Body>& b2_=Body::byId(I->getId2(),scene);
-
-			if(!b1_ || !b2_){ LOG_DEBUG("Body #"<<(b1_?I->getId2():I->getId1())<<" vanished, erasing intr #"<<I->getId1()<<"+#"<<I->getId2()<<"!"); scene->interactions->requestErase(I->getId1(),I->getId2(),/*force*/true); continue; }
-
-			// we know there is no geometry functor already, take the short path
-			if(!I->functorCache.geomExists) { assert(!I->isReal()); continue; }
-			// no interaction geometry for either of bodies; no interaction possible
-			if(!b1_->shape || !b2_->shape) { assert(!I->isReal()); continue; }
-
-			bool swap=false;
-			// InteractionGeometryDispatcher
-			if(!I->functorCache.geom || !I->functorCache.phys){
-				I->functorCache.geom=geomDispatcher->getFunctor2D(b1_->shape,b2_->shape,swap);
-				// returns NULL ptr if no functor exists; remember that and shortcut
-				if(!I->functorCache.geom) { I->functorCache.geomExists=false; continue; }
-			}
-			// arguments for the geom functor are in the reverse order (dispatcher would normally call goReverse).
-			// we don't remember the fact that is reverse, so we swap bodies within the interaction
-			// and can call go in all cases
-			if(swap){I->swapOrder();}
-			// body pointers must be updated, in case we swapped
-			const shared_ptr<Body>& b1=Body::byId(I->getId1(),scene);
-			const shared_ptr<Body>& b2=Body::byId(I->getId2(),scene);
-
-			assert(I->functorCache.geom);
-			bool wasReal=I->isReal();
-			bool geomCreated;
-			if(!scene->isPeriodic) geomCreated=I->functorCache.geom->go(b1->shape,b2->shape, *b1->state, *b2->state, Vector3r::Zero(), /*force*/false, I);
-			else{ // handle periodicity
-				Vector3r shift2(I->cellDist[0]*cellSize[0],I->cellDist[1]*cellSize[1],I->cellDist[2]*cellSize[2]);
-
-				// in sheared cell, apply shear on the mutual position as well
-				shift2=scene->cell->shearPt(shift2);
-				/* suggested change to avoid one matrix multiplication (with Hsize updated in cell ofc), I'll make the change cleanly if ok.
-					Same sorts of simplifications are possible in many places. Just putting one example here.
-					Hsize will contain colums with transformed base vectors
-					Matrix3r Hsize(scene->cell->refSize[0],scene->cell->refSize[1],scene->cell->refSize[2]); Hsize=scene->cell->trsf*Hsize;
-					Vector3r shift3((Real) I->cellDist[0]*Hsize.GetColumn(0)+(Real)I->cellDist[1]*Hsize.GetColumn(1)+(Real)I->cellDist[2]*Hsize.GetColumn(2));
-					if ((Omega::instance().getCurrentIteration() % 100 == 0)) LOG_DEBUG(shift2 << " vs " << shift3);
-				*/
-
-				geomCreated=I->functorCache.geom->go(b1->shape,b2->shape,*b1->state,*b2->state,shift2,/*force*/false,I);
-			}
-			if(!geomCreated){
-				if(wasReal) LOG_WARN("InteractionGeometryFunctor returned false on existing interaction!");
-				if(wasReal) scene->interactions->requestErase(I->getId1(),I->getId2()); // fully created interaction without geometry is reset and perhaps erased in the next step
-				continue; // in any case don't care about this one anymore
-			}
-
-			// InteractionPhysicsDispatcher
-			if(!I->functorCache.phys){
-				I->functorCache.phys=physDispatcher->getFunctor2D(b1->material,b2->material,swap);
-				assert(!swap); // InteractionPhysicsEngineUnits are symmetric
-			}
-			//assert(I->functorCache.phys);
-			if(!I->functorCache.phys){
-				throw std::runtime_error("Undefined or ambiguous InteractionPhysics dispatch for types "+b1->material->getClassName()+" and "+b2->material->getClassName()+".");
-			}
-			I->functorCache.phys->go(b1->material,b2->material,I);
-			assert(I->interactionPhysics);
-
-			if(!wasReal) I->iterMadeReal=scene->currentIteration; // mark the interaction as created right now
-
-			// LawDispatcher
-			// populating constLaw cache must be done after geom and physics dispatchers have been called, since otherwise the interaction
-			// would not have interactionGeometry and interactionPhysics yet.
+		if(removeUnseenIntrs && !I->isReal() && I->iterLastSeen<scene->currentIteration) {
+			eraseAfterLoop(I->getId1(),I->getId2());
+			continue;
+		}
+
+		const shared_ptr<Body>& b1_=Body::byId(I->getId1(),scene);
+		const shared_ptr<Body>& b2_=Body::byId(I->getId2(),scene);
+
+		if(!b1_ || !b2_){ LOG_DEBUG("Body #"<<(b1_?I->getId2():I->getId1())<<" vanished, erasing intr #"<<I->getId1()<<"+#"<<I->getId2()<<"!"); scene->interactions->requestErase(I->getId1(),I->getId2(),/*force*/true); continue; }
+
+		// we know there is no geometry functor already, take the short path
+		if(!I->functorCache.geomExists) { assert(!I->isReal()); continue; }
+		// no interaction geometry for either of bodies; no interaction possible
+		if(!b1_->shape || !b2_->shape) { assert(!I->isReal()); continue; }
+
+		bool swap=false;
+		// InteractionGeometryDispatcher
+		if(!I->functorCache.geom || !I->functorCache.phys){
+			I->functorCache.geom=geomDispatcher->getFunctor2D(b1_->shape,b2_->shape,swap);
+			// returns NULL ptr if no functor exists; remember that and shortcut
+			if(!I->functorCache.geom) { I->functorCache.geomExists=false; continue; }
+		}
+		// arguments for the geom functor are in the reverse order (dispatcher would normally call goReverse).
+		// we don't remember the fact that is reverse, so we swap bodies within the interaction
+		// and can call go in all cases
+		if(swap){I->swapOrder();}
+		// body pointers must be updated, in case we swapped
+		const shared_ptr<Body>& b1=Body::byId(I->getId1(),scene);
+		const shared_ptr<Body>& b2=Body::byId(I->getId2(),scene);
+
+		assert(I->functorCache.geom);
+		bool wasReal=I->isReal();
+		bool geomCreated;
+		if(!scene->isPeriodic) geomCreated=I->functorCache.geom->go(b1->shape,b2->shape, *b1->state, *b2->state, Vector3r::Zero(), /*force*/false, I);
+		else{ // handle periodicity
+			Vector3r shift2(I->cellDist[0]*cellSize[0],I->cellDist[1]*cellSize[1],I->cellDist[2]*cellSize[2]);
+
+			// in sheared cell, apply shear on the mutual position as well
+			shift2=scene->cell->shearPt(shift2);
+			/* suggested change to avoid one matrix multiplication (with Hsize updated in cell ofc), I'll make the change cleanly if ok.
+				Same sorts of simplifications are possible in many places. Just putting one example here.
+				Hsize will contain colums with transformed base vectors
+				Matrix3r Hsize(scene->cell->refSize[0],scene->cell->refSize[1],scene->cell->refSize[2]); Hsize=scene->cell->trsf*Hsize;
+				Vector3r shift3((Real) I->cellDist[0]*Hsize.GetColumn(0)+(Real)I->cellDist[1]*Hsize.GetColumn(1)+(Real)I->cellDist[2]*Hsize.GetColumn(2));
+				if ((Omega::instance().getCurrentIteration() % 100 == 0)) LOG_DEBUG(shift2 << " vs " << shift3);
+			*/
+
+			geomCreated=I->functorCache.geom->go(b1->shape,b2->shape,*b1->state,*b2->state,shift2,/*force*/false,I);
+		}
+		if(!geomCreated){
+			if(wasReal) LOG_WARN("InteractionGeometryFunctor returned false on existing interaction!");
+			if(wasReal) scene->interactions->requestErase(I->getId1(),I->getId2()); // fully created interaction without geometry is reset and perhaps erased in the next step
+			continue; // in any case don't care about this one anymore
+		}
+
+		// InteractionPhysicsDispatcher
+		if(!I->functorCache.phys){
+			I->functorCache.phys=physDispatcher->getFunctor2D(b1->material,b2->material,swap);
+			assert(!swap); // InteractionPhysicsEngineUnits are symmetric
+		}
+		//assert(I->functorCache.phys);
+		if(!I->functorCache.phys){
+			throw std::runtime_error("Undefined or ambiguous InteractionPhysics dispatch for types "+b1->material->getClassName()+" and "+b2->material->getClassName()+".");
+		}
+		I->functorCache.phys->go(b1->material,b2->material,I);
+		assert(I->interactionPhysics);
+
+		if(!wasReal) I->iterMadeReal=scene->currentIteration; // mark the interaction as created right now
+
+		// LawDispatcher
+		// populating constLaw cache must be done after geom and physics dispatchers have been called, since otherwise the interaction
+		// would not have interactionGeometry and interactionPhysics yet.
+		if(!I->functorCache.constLaw){
+			I->functorCache.constLaw=lawDispatcher->getFunctor2D(I->interactionGeometry,I->interactionPhysics,swap);
 			if(!I->functorCache.constLaw){
-				I->functorCache.constLaw=lawDispatcher->getFunctor2D(I->interactionGeometry,I->interactionPhysics,swap);
-				if(!I->functorCache.constLaw){
-					LOG_FATAL("None of given Law2 functors can handle interaction #"<<I->getId1()<<"+"<<I->getId2()<<", types geom:"<<I->interactionGeometry->getClassName()<<"="<<I->interactionGeometry->getClassIndex()<<" and phys:"<<I->interactionPhysics->getClassName()<<"="<<I->interactionPhysics->getClassIndex()<<" (LawDispatcher::getFunctor2D returned empty functor)");
-					//abort();
-					exit(1);
-				}
-				assert(!swap); // reverse call would make no sense, as the arguments are of different types
-			}
-		  	assert(I->functorCache.constLaw);
-			I->functorCache.constLaw->go(I->interactionGeometry,I->interactionPhysics,I.get(),scene);
-		#else
-			const shared_ptr<Body>& b1=Body::byId(I->getId1(),scene);
-			const shared_ptr<Body>& b2=Body::byId(I->getId2(),scene);
-			// InteractionGeometryDispatcher
-			bool wasReal=I->isReal();
-			bool geomCreated =
-				b1->shape && b2->shape && // some bodies do not have shape
-				geomDispatcher->operator()(b1->shape, b2->shape, *b1->state, *b2->state, Vector3r::Zero(), I);
-			// FIXME: port from the part above
-			if(scene->isPeriodic) { LOG_FATAL(__FILE__ ": Periodicity not handled without DISPATCH_CACHE."); abort(); }
-			if(!geomCreated){
-				if(wasReal) *scene->interactions->requestErase(I->getId1(),I->getId2());
-				continue;
-			}
-			// InteractionPhysicsDispatcher
-			// geom may have swapped bodies, get bodies again
-			physDispatcher->operator()(Body::byId(I->getId1(),scene)->material, Body::byId(I->getId2(),scene)->material,I);
-			// LawDispatcher
-			lawDispatcher->operator()(I->interactionGeometry,I->interactionPhysics,I.get(),scene);
-			if(!I->isReal() && I->isFresh(scene)) LOG_WARN("Law functor deleted interaction that was just created. Please report bug: either this message is spurious, or the functor (or something else) is buggy.");
-		#endif
+				LOG_FATAL("None of given Law2 functors can handle interaction #"<<I->getId1()<<"+"<<I->getId2()<<", types geom:"<<I->interactionGeometry->getClassName()<<"="<<I->interactionGeometry->getClassIndex()<<" and phys:"<<I->interactionPhysics->getClassName()<<"="<<I->interactionPhysics->getClassIndex()<<" (LawDispatcher::getFunctor2D returned empty functor)");
+				//abort();
+				exit(1);
+			}
+			assert(!swap); // reverse call would make no sense, as the arguments are of different types
+		}
+		assert(I->functorCache.constLaw);
+		I->functorCache.constLaw->go(I->interactionGeometry,I->interactionPhysics,I.get(),scene);
 
 		// process callbacks for this interaction
 		if(!I->isReal()) continue; // it is possible that Law2_ functor called requestErase, hence this check

=== modified file 'py/system.py'
--- py/system.py	2010-06-04 15:26:30 +0000
+++ py/system.py	2010-06-06 10:18:07 +0000
@@ -253,6 +253,30 @@
 	info=yade.remote.GenericTCPServer(handler=yade.remote.InfoSocketProvider,title='TCP info provider',cookie=False,minPort=21000)
 	sys.stdout.flush()
 
+# inspired by http://crunchyfrog.googlecode.com/svn/tags/0.3.4/utils/command/build_manpage.py
+# many thanks
+
+if 0: # not yet used
+	class ManPageFormatter(optparse.HelpFormatter):
+		def __init__(self,indent_increment=2,max_help_position=24,width=None,short_first=1):
+			optparse.HelpFormatter.__init__(self, indent_increment,max_help_position, width, short_first)
+		def _markup(self, txt):
+			return txt.replace('-', '\\-')
+		def format_usage(self, usage):
+			return self._markup(usage)
+		def format_heading(self, heading):
+			if self.level == 0:
+				return ''
+			return '.TP\n%s\n' % self._markup(heading.upper())
+		def format_option(self, option):
+			result = []
+			opts = self.option_strings[option]
+			result.append('.TP\n.B %s\n' % self._markup(opts))
+			if option.help:
+				help_text = '%s\n' % self._markup(self.expand_default(option))
+				result.append(help_text)
+			return ''.join(result)
+
 
 # consistency check
 # if there are no serializables, then plugins were not loaded yet, probably

=== added file 'scripts/debian-packages'
--- scripts/debian-packages	1970-01-01 00:00:00 +0000
+++ scripts/debian-packages	2010-06-06 10:18:07 +0000
@@ -0,0 +1,36 @@
+#!/bin/sh
+# prepare sources for building debian packages
+# copy this script to a clean directory and run
+set -e -x
+
+RELEASE="0.50rc1" # version we are preparing packages for
+KEYID=62A21250  # key ID of the creator (password will be asked)
+DISTS="hardy karmic lucid"
+
+TOP=`pwd`
+[ -d yade-$RELEASE.bzr ] || bzr co --lightweight lp:yade yade-$RELEASE.bzr
+rm -rf yade-$RELEASE; cp -r yade-$RELEASE.bzr yade-$RELEASE; rm -rf yade-$RELEASE/.bzr
+tar -c yade-$RELEASE | gzip > yade-${RELEASE}_$RELEASE.orig.tar.gz
+cd yade-$RELEASE
+echo $RELEASE > RELEASE
+NPKGS=0 # track number of packages; the first one will have source included
+for DIST in $DISTS; do
+	scripts/debian-prep $DIST
+	if [ $NPKGS -eq 0 ]; then
+		UPLOAD=-sa # the first package is uploaded with upstream source
+	else
+		UPLOAD=-sd
+	fi
+	debuild -S $UPLOAD -k$KEYID -I;
+	NPKGS=$(( $NPKGS + 1 ))
+done
+
+cd $TOP
+
+for CHANGES in `ls -tr yade-${RELEASE}_$RELEASE-*_source.changes` in $DISTS; do
+	dput ppa:yade-users/ppa $CHANGES
+done
+
+
+
+

=== modified file 'scripts/debian-prep'
--- scripts/debian-prep	2010-05-28 20:57:41 +0000
+++ scripts/debian-prep	2010-06-06 10:18:07 +0000
@@ -34,12 +34,12 @@
 
 # write debian/changelog
 open('debian/changelog','w').write(
-'''yade-%s (1~%s) %s; urgency=low
+'''yade-%s (%s-%s) %s; urgency=low
 
   * Automatic debian changelog entry for yade-%s
 
  -- Václav Šmilauer <eudoxos@xxxxxxxx>  %s
-'''%(VERSION,DISTRIBUTION,DISTRIBUTION,VERSION,time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime())))
+'''%(VERSION,VERSION,DISTRIBUTION,DISTRIBUTION,VERSION,time.strftime("%a, %d %b %Y %H:%M:%S +0000",time.gmtime())))
 
 # remove some generated files
 for p in ('doc/doxygen','doc/sphinx/_build','tags'):