← Back to team overview

yade-dev team mailing list archive

[Branch ~yade-dev/yade/trunk] Rev 2295: 1. Fix some spiral projection functions

 

------------------------------------------------------------
revno: 2295
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Fri 2010-06-18 15:02:01 +0200
message:
  1. Fix some spiral projection functions
  2. Add manpage generation to yade and yade-multi
  3. Add manpages to debian packaging, including alternatives (man yade -> man yade-bzr2284 etc)
removed:
  debian/yade.sgml
added:
  py/manpage.py
modified:
  core/main/main.py.in
  core/main/yade-multi.in
  debian/rules
  debian/yade-dbg.postinst-template
  debian/yade.postinst-template
  doc/sphinx/conf.py
  doc/sphinx/formulation.rst
  py/SConscript
  py/_eudoxos.cpp
  py/config.py.in


--
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 'core/main/main.py.in'
--- core/main/main.py.in	2010-04-23 11:23:15 +0000
+++ core/main/main.py.in	2010-06-18 13:02:01 +0000
@@ -2,7 +2,7 @@
 # encoding: utf-8
 # syntax:python
 
-import sys,os,os.path
+import sys,os,os.path,time
 # get yade path (allow YADE_PREFIX to override)
 prefix,suffix='${runtimePREFIX}' if not os.environ.has_key('YADE_PREFIX') else os.environ['YADE_PREFIX'],'${SUFFIX}'
 sys.path.append(os.path.join(prefix,'lib','yade'+suffix,'py'))
@@ -17,7 +17,7 @@
 
 # handle command-line options first
 import optparse
-par=optparse.OptionParser(usage='%prog [options] [ simulation.xml[.bz2] | script.py [script options]]',prog='Yade',version='%s (%s)'%(version,','.join(features)),description="Yade: open-source platform for dynamic compuations. Homepage http://www.yade-dem.org, code hosted at http://www.launchpad.net/yade. This is version %s (with features %s)."%(version,','.join(features)))
+par=optparse.OptionParser(usage='%prog [options] [ simulation.xml[.bz2] | script.py [script options]]',prog=os.path.basename(sys.argv[0]),version='%s (%s)%s'%(version,','.join(features),' with debugging symbols' if debug else ''),description="Yade: open-source platform for dynamic compuations. Homepage http://www.yade-dem.org, code hosted at http://www.launchpad.net/yade. This is version %s (with features %s %s)."%(version,','.join(features),', with debugging symbols' if debug else ''))
 par.add_option('-j','--threads',help='Number of OpenMP threads to run; defaults to number of cores. Equivalent to setting OMP_NUM_THREADS environment variable.',dest='threads',type='int')
 par.add_option('--update',help='Update deprecated class names in given script(s) using text search & replace. Changed files will be backed up with ~ suffix. Exit when done without running any simulation.',dest='updateScripts',action='store_true')
 par.add_option('--nice',help='Increase nice level (i.e. decrease priority) by given number.',dest='nice',type='int')
@@ -27,6 +27,7 @@
 if debug:
 	par.add_option('--no-gdb',help='Do not show backtrace when yade crashes.',dest='noGdb',action='store_true',)
 par.add_option('-n',help="Run without graphical interface (equivalent to unsetting the DISPLAY environment variable)",dest='nogui',action='store_true')
+par.add_option('--generate-manpage',help="Generate man page documenting this program and exit",dest='manpage',metavar='FILE')
 
 opts,args=par.parse_args()
 # c++ boot code checks for YADE_DEBUG at some places; debug verbosity is equivalent
@@ -39,35 +40,13 @@
 
 sys.stderr.write('Welcome to Yade '+version+'\n')
 
-try:
-	# initialization and c++ plugins import
-	import yade
-	# other parts we will need soon
-	import yade.config
-	import yade.wrapper
-	import yade.log
-	import yade.system
-#import yade.plot
-except AttributeError:
-	print """
-==========================================
-======== ERROR: read carefully! ==========
-==========================================
-
-There was AttributeError while importing yade module.
-If you are running Ubuntu 9.10 (karmic) or 10.04 (lucid),
-you just hit a known bug
-https://bugs.launchpad.net/ubuntu/+source/boost1.38/+bug/457688
-
-You can work around this bug by updating boost from yade's updated repository
-(as per https://bugs.launchpad.net/ubuntu/+source/boost1.38/+bug/457688/comments/6)
-by issuing the following command:
-
-  sudo add-apt-repository ppa:yade-users/external && sudo apt-get update && sudo apt-get upgrade
-
-You should not need to recompile afterwards.
-"""
-	sys.exit(1)
+# initialization and c++ plugins import
+import yade
+# other parts we will need soon
+import yade.config
+import yade.wrapper
+import yade.log
+import yade.system
 
 
 # continue option processing
@@ -75,6 +54,11 @@
 if opts.updateScripts:
 	yade.system.updateScripts(args)
 	sys.exit(0)
+if opts.manpage:
+	import yade.manpage
+	yade.manpage.generate_manpage(par,yade.config.metadata,opts.manpage,section=1,seealso='yade%s-multi (1)'%suffix)
+	print 'Manual page %s generated.'%opts.manpage
+	sys.exit(0)
 if opts.nice:
 	os.nice(opts.nice)
 if yade.config.debug and opts.noGdb:

=== modified file 'core/main/yade-multi.in'
--- core/main/yade-multi.in	2010-06-06 10:18:07 +0000
+++ core/main/yade-multi.in	2010-06-18 13:02:01 +0000
@@ -6,7 +6,7 @@
 import os, sys, thread, time, logging, pipes
 
 ## replaced by scons automatically
-prefix,suffix='${runtimePREFIX}' if not os.environ.has_key('YADE_PREFIX') else os.environ('YADE_PREFIX'),'${SUFFIX}'
+prefix,suffix='${runtimePREFIX}' if not os.environ.has_key('YADE_PREFIX') else os.environ['YADE_PREFIX'],'${SUFFIX}'
 sys.path.append(os.path.join(prefix,'lib','yade'+suffix,'py'))
 executable=os.path.join(prefix,'bin','yade'+suffix)
 ## we just need this ...
@@ -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 https://yade-dem.org/sphinx/user.html#batch-queuing-and-execution-yade-multi for details.')
+parser=optparse.OptionParser(usage='%prog [options] TABLE SIMULATION.py',description='%prog runs yade simulation multiple times with different parameters.\n\nSee 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')
@@ -172,9 +172,18 @@
 parser.add_option('--gnuplot',dest='gnuplotOut',help='Gnuplot file where gnuplot from all jobs should be put together',default=None,metavar='FILE')
 parser.add_option('--dry-run',action='store_true',dest='dryRun',help='Do not actually run (useful for getting gnuplot only, for instance)',default=False)
 parser.add_option('--http-wait',action='store_true',dest='httpWait',help='Do not quit if still serving overview over http repeatedly',default=False)
+parser.add_option('--generate-manpage',help='Generate man page documenting this program and exit',dest='manpage',metavar='FILE')
 opts,args=parser.parse_args()
 logFormat,lineList,maxJobs,nice,executable,gnuplotOut,dryRun,httpWait,globalLog=opts.logFormat,opts.lineList,opts.maxJobs,opts.nice,opts.executable,opts.gnuplotOut,opts.dryRun,opts.httpWait,opts.globalLog
 
+if opts.manpage:
+	import yade.manpage
+	yade.config.metadata['short_desc']='batch system for computational platform Yade'
+	yade.config.metadata['long_desc']='Manage batches of computation jobs for the Yade platform; batches are described using text-file tables with parameters which are passed to individual runs of yade. Jobs are being run with pre-defined number of computational cores as soon as the required number of cores is available. Logs of all computations are stored in files and the batch progress can be watched online at (usually) http://localhost:9080. Unless overridden, the executable yade%s is used to run jobs.'%(yade.config.suffix)
+	yade.manpage.generate_manpage(parser,yade.config.metadata,opts.manpage,section=1,seealso='yade%s (1)\n.br\nhttps://yade-dem.org/sphinx/user.html#batch-queuing-and-execution-yade-multi'%suffix)
+	print 'Manual page %s generated.'%opts.manpage
+	sys.exit(0)
+
 if globalLog:
 	sys.stderr=open(globalLog,"w")
 	sys.stdout=sys.stderr

=== modified file 'debian/rules'
--- debian/rules	2010-06-13 21:28:46 +0000
+++ debian/rules	2010-06-18 13:02:01 +0000
@@ -25,7 +25,7 @@
 	# Add here commands to compile the package.
 	#$(MAKE)
 	## eudoxos: noting to be done here, will be done at the same time as installation
-	docbook-to-man debian/yade.sgml > yade.1
+	#docbook-to-man debian/yade.sgml > yade.1
 	touch $@
 
 clean:
@@ -60,6 +60,11 @@
 	cp -r examples scripts debian/yade${_VERSION}/usr/share/doc/yade${_VERSION}
 	# 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-query -W python-sphinx; then cd doc/sphinx; PYTHONPATH=. YADE_PREFIX=../../debian/yade${_VERSION}/usr/ ../../debian/yade${_VERSION}/usr/bin/yade${_VERSION} yadeSphinx.py; cd _build/latex; xelatex Yade.tex; xelatex Yade.tex; xelatex Yade.tex; cd ../..; mkdir -p ../../debian/yade${_VERSION}-doc/usr/share/doc/yade${_VERSION}; cp -r _build/html _build/latex/Yade.pdf ../../debian/yade${_VERSION}-doc/usr/share/doc/yade${_VERSION}; else echo "Not building HTML documentation, since the python-sphinx package is not installed"; fi
+	# generate manpages
+	YADE_PREFIX=debian/yade${_VERSION}/usr debian/yade${_VERSION}/usr/bin/yade${_VERSION} --generate-manpage yade${_VERSION}.1
+	YADE_PREFIX=debian/yade${_VERSION}/usr debian/yade${_VERSION}/usr/bin/yade${_VERSION}-multi --generate-manpage yade${_VERSION}-multi.1
+	YADE_PREFIX=debian/yade${_VERSION}-dbg/usr debian/yade${_VERSION}-dbg/usr/bin/yade${_VERSION}-dbg --generate-manpage yade${_VERSION}-dbg.1
+	YADE_PREFIX=debian/yade${_VERSION}-dbg/usr debian/yade${_VERSION}-dbg/usr/bin/yade${_VERSION}-dbg-multi --generate-manpage yade${_VERSION}-dbg-multi.1
 
 check: install
 	dh_testdir
@@ -90,7 +95,8 @@
 #	dh_installinit
 #	dh_installcron
 #	dh_installinfo
-	dh_installman
+	dh_installman -p yade${_VERSION} yade${_VERSION}.1 yade${_VERSION}-multi.1
+	dh_installman -p yade${_VERSION}-dbg yade${_VERSION}-dbg.1 yade${_VERSION}-dbg-multi.1
 	dh_link
 	dh_strip --exclude=yade${_VERSION}-dbg   # don't strip the debug package
 	dh_compress

=== modified file 'debian/yade-dbg.postinst-template'
--- debian/yade-dbg.postinst-template	2010-01-10 09:09:32 +0000
+++ debian/yade-dbg.postinst-template	2010-06-18 13:02:01 +0000
@@ -20,7 +20,7 @@
 
 case "$1" in
     configure)
-	 	update-alternatives --install /usr/bin/yade-dbg yade-dbg /usr/bin/yade@_VERSION@-dbg @PRIORITY@ --slave /usr/bin/yade-dbg-multi yade-dbg-multi /usr/bin/yade@_VERSION@-dbg-multi
+	 	update-alternatives --install /usr/bin/yade-dbg yade-dbg /usr/bin/yade@_VERSION@-dbg @PRIORITY@ --slave /usr/bin/yade-dbg-multi yade-dbg-multi /usr/bin/yade@_VERSION@-dbg-multi --slave /usr/share/man/man1/yade-dbg.1.gz yade-dbg.1.gz /usr/share/man/man1/yade@_VERSION@xxxxxxxxx --slave /usr/share/man/man1/yade-dbg-multi.1.gz yade-dbg-multi.1.gz /usr/share/man/man1/yade@_VERSION@xxxxxxxxxxxxxxx
     ;;
 
     abort-upgrade|abort-remove|abort-deconfigure)

=== modified file 'debian/yade.postinst-template'
--- debian/yade.postinst-template	2010-01-10 09:09:32 +0000
+++ debian/yade.postinst-template	2010-06-18 13:02:01 +0000
@@ -20,7 +20,7 @@
 
 case "$1" in
     configure)
-	 	update-alternatives --install /usr/bin/yade yade /usr/bin/yade@_VERSION@ @PRIORITY@ --slave /usr/bin/yade-multi yade-multi /usr/bin/yade@_VERSION@-multi
+	 	update-alternatives --install /usr/bin/yade yade /usr/bin/yade@_VERSION@ @PRIORITY@ --slave /usr/bin/yade-multi yade-multi /usr/bin/yade@_VERSION@-multi --slave /usr/share/man/man1/yade.1.gz yade.1.gz /usr/share/man/man1/yade@_VERSION@xxxxx --slave /usr/share/man/man1/yade-multi.1.gz yade-multi.1.gz /usr/share/man/man1/yade@_VERSION@xxxxxxxxxxx
     ;;
 
     abort-upgrade|abort-remove|abort-deconfigure)

=== removed file 'debian/yade.sgml'
--- debian/yade.sgml	2007-03-31 06:18:17 +0000
+++ debian/yade.sgml	1970-01-01 00:00:00 +0000
@@ -1,156 +0,0 @@
-<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [
-
-<!-- Process this file with docbook-to-man to generate an nroff manual
-     page: `docbook-to-man manpage.sgml > manpage.1'.  You may view
-     the manual page with: `docbook-to-man manpage.sgml | nroff -man |
-     less'.  A typical entry in a Makefile or Makefile.am is:
-
-manpage.1: manpage.sgml
-	docbook-to-man $< > $@
-
-    
-	The docbook-to-man binary is found in the docbook-to-man package.
-	Please remember that if you create the nroff version in one of the
-	debian/rules file targets (such as build), you will need to include
-	docbook-to-man in your Build-Depends control field.
-
-  -->
-
-  <!-- Fill in your name for FIRSTNAME and SURNAME. -->
-  <!ENTITY dhfirstname "<firstname>FIRSTNAME</firstname>">
-  <!ENTITY dhsurname   "<surname>SURNAME</surname>">
-  <!-- Please adjust the date whenever revising the manpage. -->
-  <!ENTITY dhdate      "<date>březen  8, 2007</date>">
-  <!-- SECTION should be 1-8, maybe w/ subsection other parameters are
-       allowed: see man(7), man(1). -->
-  <!ENTITY dhsection   "<manvolnum>SECTION</manvolnum>">
-  <!ENTITY dhemail     "<email>eudoxos@xxxxxxxx</email>">
-  <!ENTITY dhusername  "Vaclav Smilauer">
-  <!ENTITY dhucpackage "<refentrytitle>YADE</refentrytitle>">
-  <!ENTITY dhpackage   "yade">
-
-  <!ENTITY debian      "<productname>Debian</productname>">
-  <!ENTITY gnu         "<acronym>GNU</acronym>">
-  <!ENTITY gpl         "&gnu; <acronym>GPL</acronym>">
-]>
-
-<refentry>
-  <refentryinfo>
-    <address>
-      &dhemail;
-    </address>
-    <author>
-      &dhfirstname;
-      &dhsurname;
-    </author>
-    <copyright>
-      <year>2003</year>
-      <holder>&dhusername;</holder>
-    </copyright>
-    &dhdate;
-  </refentryinfo>
-  <refmeta>
-    &dhucpackage;
-
-    &dhsection;
-  </refmeta>
-  <refnamediv>
-    <refname>&dhpackage;</refname>
-
-    <refpurpose>program to do something</refpurpose>
-  </refnamediv>
-  <refsynopsisdiv>
-    <cmdsynopsis>
-      <command>&dhpackage;</command>
-
-      <arg><option>-e <replaceable>this</replaceable></option></arg>
-
-      <arg><option>--example <replaceable>that</replaceable></option></arg>
-    </cmdsynopsis>
-  </refsynopsisdiv>
-  <refsect1>
-    <title>DESCRIPTION</title>
-
-    <para>This manual page documents briefly the
-      <command>&dhpackage;</command> and <command>bar</command>
-      commands.</para>
-
-    <para>This manual page was written for the &debian; distribution
-      because the original program does not have a manual page.
-      Instead, it has documentation in the &gnu;
-      <application>Info</application> format; see below.</para>
-
-    <para><command>&dhpackage;</command> is a program that...</para>
-
-  </refsect1>
-  <refsect1>
-    <title>OPTIONS</title>
-
-    <para>These programs follow the usual &gnu; command line syntax,
-      with long options starting with two dashes (`-').  A summary of
-      options is included below.  For a complete description, see the
-      <application>Info</application> files.</para>
-
-    <variablelist>
-      <varlistentry>
-        <term><option>-h</option>
-          <option>--help</option>
-        </term>
-        <listitem>
-          <para>Show summary of options.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
-        <term><option>-v</option>
-          <option>--version</option>
-        </term>
-        <listitem>
-          <para>Show version of program.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
-  </refsect1>
-  <refsect1>
-    <title>SEE ALSO</title>
-
-    <para>bar (1), baz (1).</para>
-
-    <para>The programs are documented fully by <citetitle>The Rise and
-      Fall of a Fooish Bar</citetitle> available via the
-      <application>Info</application> system.</para>
-  </refsect1>
-  <refsect1>
-    <title>AUTHOR</title>
-
-    <para>This manual page was written by &dhusername; &dhemail; for
-      the &debian; system (but may be used by others).  Permission is
-      granted to copy, distribute and/or modify this document under
-      the terms of the &gnu; General Public License, Version 2 any 
-	  later version published by the Free Software Foundation.
-    </para>
-	<para>
-	  On Debian systems, the complete text of the GNU General Public
-	  License can be found in /usr/share/common-licenses/GPL.
-	</para>
-
-  </refsect1>
-</refentry>
-
-<!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-omittag:t
-sgml-shorttag:t
-sgml-minimize-attributes:nil
-sgml-always-quote-attributes:t
-sgml-indent-step:2
-sgml-indent-data:t
-sgml-parent-document:nil
-sgml-default-dtd-file:nil
-sgml-exposed-tags:nil
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-End:
--->
-
-

=== modified file 'doc/sphinx/conf.py'
--- doc/sphinx/conf.py	2010-06-12 20:39:00 +0000
+++ doc/sphinx/conf.py	2010-06-18 13:02:01 +0000
@@ -156,7 +156,7 @@
 def replaceLaTeX(s):
 	# replace single non-escaped dollars $...$ by :math:`...`
 	# then \$ by single $
-	s=re.sub(r'(?<!\\)\$([^\$]+)(?<!\\)\$',r':math:`\1`',s)
+	s=re.sub(r'(?<!\\)\$([^\$]+)(?<!\\)\$',r'\ :math:`\1`\ ',s)
 	return re.sub(r'\\\$',r'$',s)
 
 def fixSrc(app,docname,source):

=== modified file 'doc/sphinx/formulation.rst'
--- doc/sphinx/formulation.rst	2010-06-13 21:25:46 +0000
+++ doc/sphinx/formulation.rst	2010-06-18 13:02:01 +0000
@@ -108,10 +108,10 @@
 
 .. FIXME table
 
-=============== ========================================================
-($\leq$)        the sorting order with the left neighbor is correct, or
-($||$)          the element is at the beginning of the sequence.
-=============== ========================================================
+=================== ========================================================
+($\leq$)            the sorting order with the left neighbor is correct, or
+($||$)              the element is at the beginning of the sequence.
+=================== ========================================================
 
 We start at the leftmost element (the current element is marked $\currelem{i}$)
 
@@ -684,11 +684,11 @@
 .. math::
 	:label: eq-dt-omega
 	
-	\omega^{(1)}=\sqrt{\frac{m}{K}}
+	\omega^{(1)}=\sqrt{\frac{K}{m}}
 
 does not depend on initial conditions. Since there is one single mass, $\omega_{\rm max}^{(1)}=\omega^{(1)}$. Plugging :eq:`eq-dt-omega` into :eq:`eq-dt-angular`, we obtain
 
-.. math:: \Dtcr^{(1)}=2/\omega_{\rm max}^{(1)}=2\sqrt{K/m}
+.. math:: \Dtcr^{(1)}=2/\omega_{\rm max}^{(1)}=2\sqrt{m/K}
 
 for a single oscillator.
 	
@@ -903,13 +903,13 @@
 
 Sorting starts from the first element in the cell, i.e. right of $||$, and inverts elements as in the aperiodic variant. The rules are, however, more complicated due to the presence of the boundary $||$:
 
-======================== ==============================================================
-($\leq$)                 stop inverting if neighbors are ordered;
-($||\bullet$)            current element left of $||$ is below 0 (lower period boundary); in this case, decrement element's period, decrease its coordinate by $s_x$ and move $||$ right;
-($\bullet||$)            current element right of $||$ is above $s_x$ (upper period boundary); increment element's period, increase its coordinate by $s_x$ and move $||$ left;
-($\crossBound$)          inversion across $||$ must subtract $s_x$ from the left coordinate during comparison. If the elements are not in order, they are swapped, but they must have their periods changed as they traverse $||$. Apply ($||\circ$) if necessary;
-($||\circ$)              if after ($\crossBound$) the element that is now right of $||$ has $x_i<s_x$, decrease its coordinate by $s_x$ and decrement its period. Do not move $||$.
-======================== ==============================================================
+========================== ==============================================================
+($\leq$)                   stop inverting if neighbors are ordered;
+($||\bullet$)              current element left of $||$ is below 0 (lower period boundary); in this case, decrement element's period, decrease its coordinate by $s_x$ and move $||$ right;
+($\bullet||$)              current element right of $||$ is above $s_x$ (upper period boundary); increment element's period, increase its coordinate by $s_x$ and move $||$ left;
+($\crossBound$)            inversion across $||$ must subtract $s_x$ from the left coordinate during comparison. If the elements are not in order, they are swapped, but they must have their periods changed as they traverse $||$. Apply ($||\circ$) if necessary;
+($||\circ$)                if after ($\crossBound$) the element that is now right of $||$ has $x_i<s_x$, decrease its coordinate by $s_x$ and decrement its period. Do not move $||$.
+========================== ==============================================================
 
 In the first step, ($||\bullet$) is applied, and inversion with $12_2$ happens; then we stop because of ($\leq$):
 

=== modified file 'py/SConscript'
--- py/SConscript	2010-06-07 14:56:29 +0000
+++ py/SConscript	2010-06-18 13:02:01 +0000
@@ -36,6 +36,7 @@
 	env.File('export.py'),
 	env.File('post2d.py'),
 	env.File('runtime.py'),
+	env.File('manpage.py'),
 	env.File('_extraDocs.py'),
 	env.SharedLibrary('wrapper',['yadeWrapper/yadeWrapper.cpp'],SHLIBPREFIX='',LIBS=linkPlugins(['Shop','BoundDispatcher','InteractionGeometryDispatcher','InteractionPhysicsDispatcher','LawDispatcher','InteractionDispatchers','ParallelEngine','Clump','STLImporter',])),
 	env.SharedLibrary('_customConverters',['yadeWrapper/customConverters.cpp'],SHLIBPREFIX='',LIBS=env['LIBS']+linkPlugins(Split("BoundFunctor InteractionGeometryFunctor InteractionPhysicsFunctor LawFunctor")))

=== modified file 'py/_eudoxos.cpp'
--- py/_eudoxos.cpp	2010-06-17 21:13:59 +0000
+++ py/_eudoxos.cpp	2010-06-18 13:02:01 +0000
@@ -138,7 +138,7 @@
 	shared_ptr<GridContainer<FlatInteraction> > grid;
 	Real thetaSpan;
 	int axis;
-	SpiralInteractionLocator2d(Real dH_dTheta, int _axis, Real periodStart, Real theta0): axis(_axis){
+	SpiralInteractionLocator2d(Real dH_dTheta, int _axis, Real periodStart, Real theta0, Real thetaMin, Real thetaMax): axis(_axis){
 		Scene* scene=Omega::instance().getScene().get();
 		Real inf=std::numeric_limits<Real>::infinity();
 		Vector2r lo=Vector2r(inf,inf), hi(-inf,-inf);
@@ -152,6 +152,8 @@
 			if(!ge || !ph) continue;
 			Real r,h,theta;
 			boost::tie(r,h,theta)=Shop::spiralProject(ge->contactPoint,dH_dTheta,axis,periodStart,theta0);
+			if(!isnan(thetaMin) && theta<thetaMin) continue;
+			if(!isnan(thetaMax) && theta>thetaMax) continue;
 			lo=lo.cwise().min(Vector2r(r,h)); hi=hi.cwise().max(Vector2r(r,h));
 			minD0=min(minD0,ge->refLength); maxD0=max(maxD0,ge->refLength);
 			minTheta=min(minTheta,theta); maxTheta=max(maxTheta,theta);
@@ -306,7 +308,7 @@
 	py::def("particleConfinement",particleConfinement);
 	py::def("testNumpy",testNumpy);
 #ifdef YADE_VTK
-	py::class_<InteractionLocator>("InteractionLocator","Locate all (real) interactions in space by their :yref:`contact point<Dem3DofGeom::contactPoint>`. When constructed, all real interactions are spatially indexed (uses vtkPointLocator internally). Use intrsWithinDistance to use those data. \n\n.. note::\n\tData might become inconsistent with real simulation state if simulation is being run between creation of this object and spatial queries.")
+	py::class_<InteractionLocator>("InteractionLocator","Locate all (real) interactions in space by their :yref:`contact point<Dem3DofGeom::contactPoint>`. When constructed, all real interactions are spatially indexed (uses `vtkPointLocator <http://www.vtk.org/doc/release/5.4/html/a01247.html>`_ internally). Use instance methods to use those data. \n\n.. note::\n\tData might become inconsistent with real simulation state if simulation is being run between creation of this object and spatial queries.")
 		.def("intrsAroundPt",&InteractionLocator::intrsAroundPt,((python::arg("point"),python::arg("maxDist"))),"Return list of real interactions that are not further than *maxDist* from *point*.")
 		.def("macroAroundPt",&InteractionLocator::macroAroundPt,((python::arg("point"),python::arg("maxDist"),python::arg("forceVolume")=-1)),"Return tuple of averaged stress tensor (as Matrix3), average omega and average kappa values. *forceVolume* can be used (if positive) rather than the sphere (with *maxDist* radius) volume for the computation. (This is useful if *point* and *maxDist* encompass empty space that you want to avoid.)")
 		.add_property("bounds",&InteractionLocator::getBounds,"Return coordinates of lower and uppoer corner of axis-aligned abounding box of all interactions")
@@ -315,10 +317,10 @@
 #endif
 	py::class_<SpiralInteractionLocator2d>("SpiralInteractionLocator2d",
 		"Locate all real interactions in 2d plane (reduced by spiral projection from 3d, using ``Shop::spiralProject``, which is the same as :yref:`yade.utils.spiralProject`) using their :yref:`contact points<Dem3DofGeom::contactPoint>`. \n\n.. note::\n\tDo not run simulation while using this object.",
-		python::init<Real,int,Real,Real>((python::arg("dH_dTheta"),python::arg("axis")=0,python::arg("periodStart")=NaN,python::arg("theta0")=0),":Parameters:\n\n\tdH_dTheta: float\n\t\tSpiral inclination, i.e. height increase per 1 radian turn;\n\taxis: int\n\t\tAxis of rotation (0=x,1=y,2=z)\n\ttheta: float\n\t\tSpiral angle at zero height (theta intercept)\n\nSee :yref:`yade.utils.spiralProject`.")
+		python::init<Real,int,Real,Real,Real,Real>((python::arg("dH_dTheta"),python::arg("axis")=0,python::arg("periodStart")=NaN,python::arg("theta0")=0,python::arg("thetaMin")=NaN,python::arg("thetaMax")=NaN),":param float dH_dTheta: Spiral inclination, i.e. height increase per 1 radian turn;\n:param int axis: axis of rotation (0=x,1=y,2=z)\n:param float theta: spiral angle at zero height (theta intercept)\n:param float thetaMin: only interactions with $\\theta$≥\\ *thetaMin* will be considered (NaN to deactivate)\n:param float thetaMax: only interactions with $\\theta$≤\\ *thetaMax* will be considered (NaN to deactivate)\n\nSee :yref:`yade.utils.spiralProject`.")
 	)
 		.def("intrsAroundPt",&SpiralInteractionLocator2d::intrsAroundPt,(python::arg("pt2d"),python::arg("radius")),"Return list of interaction objects that are not further from *pt2d* than *radius* in the projection plane")
-		.def("macroAroundPt",&SpiralInteractionLocator2d::macroAroundPt,(python::arg("pt2d"),python::arg("radius")),"Compute macroscopic stress around given point, rotating the interaction to the projection plane first. The formula used is\n\n.. math::\n\n    \\sigma_{ij}=\\frac{1}{V}\\sum_{IJ}d^{IJ}A^{IJ}\\left[\\sigma^{N,IJ}n_i^{IJ}n_j^{IJ}+\\frac{1}{2}\\left(\\sigma_i^{T,IJ}n_j^{IJ}+\\sigma_j^{T,IJ}n_i^{IJ}\\right)\\right]\n\nwhere the sum is taken over volume $V$ containing interactions $IJ$ between spheres $I$ and $J$;\n\n* $i$, $j$ indices denote Cartesian components of vectors and tensors,\n* $d^{IJ}$ is current distance between spheres $I$ and $J$,\n* $A^{IJ}$ is area of contact $IJ$,\n* $n$ is interaction normal (unit vector pointing from center of $I$ to the center of $J$)\n* $\\sigma^{N,IJ}$  is normal stress (as scalar) in contact $IJ$,\n* $\\sigma^{T,IJ}$ is shear stress in contact $IJ$ in global coordinates.\n\n$\\sigma^{T}$ and $n$ are transformed by angle $\\theta$ as given by :yref:`yade.utils.spiralProject`. \n\nAdditionaly, computes average of :yref:`CpmPhys.omega` ($\\bar\\omega$) and :yref:`CpmPhys.kappaD` ($\\bar\\kappa_D$). *N* is the number of interactions in the volume given. \n\n:Return: tuple of (*N*,$\\tens{\\sigma}$,$\\bar\\omega$,$\\bar\\kappa_D$).\n")
+		.def("macroAroundPt",&SpiralInteractionLocator2d::macroAroundPt,(python::arg("pt2d"),python::arg("radius")),"Compute macroscopic stress around given point; the interaction ($n$ and $\\sigma^T$ are rotated to the projection plane by $\\theta$ (as given by :yref:`yade.utils.spiralProject`) first, but no skew is applied). The formula used is\n\n.. math::\n\n    \\sigma_{ij}=\\frac{1}{V}\\sum_{IJ}d^{IJ}A^{IJ}\\left[\\sigma^{N,IJ}n_i^{IJ}n_j^{IJ}+\\frac{1}{2}\\left(\\sigma_i^{T,IJ}n_j^{IJ}+\\sigma_j^{T,IJ}n_i^{IJ}\\right)\\right]\n\nwhere the sum is taken over volume $V$ containing interactions $IJ$ between spheres $I$ and $J$;\n\n* $i$, $j$ indices denote Cartesian components of vectors and tensors,\n* $d^{IJ}$ is current distance between spheres $I$ and $J$,\n* $A^{IJ}$ is area of contact $IJ$,\n* $n$ is ($\\theta$-rotated) interaction normal (unit vector pointing from center of $I$ to the center of $J$)\n* $\\sigma^{N,IJ}$  is normal stress (as scalar) in contact $IJ$,\n* $\\sigma^{T,IJ}$ is shear stress in contact $IJ$ in global coordinates and $\\theta$-rotated. \n\nAdditionaly, computes average of :yref:`CpmPhys.omega` ($\\bar\\omega$) and :yref:`CpmPhys.kappaD` ($\\bar\\kappa_D$). *N* is the number of interactions in the volume given.\n\n:return: tuple of (*N*, $\\tens{\\sigma}$, $\\bar\\omega$, $\\bar\\kappa_D$).\n")
 		.add_property("lo",&SpiralInteractionLocator2d::getLo,"Return lower corner of the rectangle containing all interactions.")
 		.add_property("hi",&SpiralInteractionLocator2d::getHi,"Return upper corner of the rectangle containing all interactions.");
 

=== modified file 'py/config.py.in'
--- py/config.py.in	2010-01-23 15:40:06 +0000
+++ py/config.py.in	2010-06-18 13:02:01 +0000
@@ -1,9 +1,10 @@
+# encoding: utf-8
 """
 Compile-time configuration for yade.
 
 Template file is processed by scons to create the actual configuration at build-time.
 """
-import os
+import os,datetime
 prefix='${runtimePREFIX}' if not os.environ.has_key('YADE_PREFIX') else os.environ['YADE_PREFIX']
 suffix='${SUFFIX}'
 libstdcxx='${libstdcxx}'
@@ -13,3 +14,31 @@
 debug=bool(${debug})
 
 libDir=prefix+'/lib/yade'+suffix
+
+# project metadata
+metadata=dict(
+	short_desc='open-source platform for dynamic computations%s'%(' (debugging version)' if debug else ''),
+	long_desc='Extensible open-source framework for discrete numerical models, focused on Discrete Element Method. The computation parts are written in c++ using flexible object model, allowing independent implementation of new alogrithms and interfaces. Python is used for rapid and concise scene construction, simulation control, postprocessing and debugging.\n\n\n\nSee http://www.yade-dem.org/ for documentation and http://www.launchpad.net/yade for the project itself.\n\nThis is version %s with features %s.'%(version,','.join(features)),
+	author='Yade Developers Team',
+	website='http://www.yade-dem.org',
+	author_contact='http://www.launchpad.net/~yade-dev',
+	mailinglist='yade-users@xxxxxxxxxxxxxxxxxxx',
+	bugtracker='http://bugs.launchpad.net/yade',
+	copyright='© 2003--%s'%(datetime.date.today().year),
+	license='''This program is free software; you can redistribute it and/or modify 
+it under the terms of the GNU General Public License as published 
+by the Free Software Foundation; either version 2 of the License, 
+or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, 
+but WITHOUT ANY WARRANTY; without even the implied warranty of 
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License 
+along with this program; if not, write to the Free Software 
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+MA 02111-1307 USA.
+''',
+)
+

=== added file 'py/manpage.py'
--- py/manpage.py	1970-01-01 00:00:00 +0000
+++ py/manpage.py	2010-06-18 13:02:01 +0000
@@ -0,0 +1,88 @@
+# coding: utf-8
+#
+# Thanks to logilab for this code.
+#
+# Copied from the logilab.common.optik_ext module (GPL-licensed) and modified for yade.
+#
+
+import optparse,time
+
+class ManHelpFormatter(optparse.HelpFormatter):
+	"""Format help using man pages ROFF format"""
+	def __init__(self,indent_increment=0,max_help_position=24,width=79,short_first=0):
+		optparse.HelpFormatter.__init__(self, indent_increment, max_help_position, width, short_first)
+	def format_heading(self, heading):
+		return '.SH %s\n' % heading.upper()
+	def format_description(self, description):
+		return description
+	def format_option(self, option):
+		try:
+			optstring = option.option_strings
+		except AttributeError:
+			optstring = self.format_option_strings(option)
+		if option.help:
+			help = ' '.join([l.strip() for l in option.help.splitlines()])
+		else:
+			help = ''
+		return '''.IP "%s"
+%s
+''' % (optstring, help)
+	def format_head(self, optparser, metadata, section=1):
+		pgm = optparser.get_prog_name()
+		short_desc = self.format_short_description(pgm, metadata['short_desc'])
+		long_desc = self.format_long_description(pgm, metadata['long_desc'])
+		return '%s\n%s\n%s\n%s' % (self.format_title(pgm, section), short_desc, self.format_synopsis(optparser), long_desc)
+	def format_title(self, pgm, section):
+		date = '-'.join([str(num) for num in time.localtime()[:3]])
+		return '.TH %s %s "%s" %s' % (pgm, section, date, pgm)
+	def format_short_description(self, pgm, short_desc):
+		return '''.SH NAME
+.B %s 
+\- %s
+''' % (pgm, short_desc.strip())
+	def _markup(self, txt):
+		"""Prepares txt to be used in man pages."""
+		return txt.replace('-', '\\-')
+	def format_synopsis(self, optparser):
+		synopsis = optparser.get_usage()
+		pgm=optparser.get_prog_name()                                    
+		if synopsis:                                                           
+			synopsis = synopsis.replace('Usage: %s '%pgm, '')                   
+			return '.SH SYNOPSIS\n.B %s\n%s\n' % (self._markup(pgm),synopsis)
+	def format_long_description(self, pgm, long_desc):
+		long_desc = '\n'.join([line.lstrip()
+								for line in long_desc.splitlines()])
+		long_desc = long_desc.replace('\n.\n', '\n\n')
+		if long_desc.lower().startswith(pgm):
+			long_desc = long_desc[len(pgm):]
+		return '''.SH DESCRIPTION
+.B %s 
+%s
+''' % (pgm, long_desc.strip())
+		 
+	def format_tail(self, metadata, seealso=None):
+		
+		return ('.SH SEE ALSO\n%s\n'%seealso if seealso else '')+'''.SH COPYRIGHT 
+%s %s
+
+%s
+
+.SH BUGS 
+Please report bugs to the project\'s bug tracker at
+.br
+%s
+
+.SH AUTHOR
+%s (%s)
+''' % (metadata['copyright'],metadata['author'],metadata['license'],metadata['bugtracker'],metadata['author'],metadata['author_contact'])
+
+
+def generate_manpage(optparser,metadata,fileOut,seealso=None,section=1):
+	"""generate a man page from an optparse parser"""
+	out=open(fileOut,'w')
+	formatter=ManHelpFormatter()
+	formatter.parser=optparser
+	out.write(formatter.format_head(optparser,metadata,section))
+	out.write(optparser.format_option_help(formatter))
+	out.write(formatter.format_tail(metadata,seealso))
+