← Back to team overview

yade-dev team mailing list archive

[svn] r1752 - in trunk: gui/py scripts scripts/test

 

Author: eudoxos
Date: 2009-04-09 12:15:52 +0200 (Thu, 09 Apr 2009)
New Revision: 1752

Modified:
   trunk/gui/py/log.cpp
   trunk/gui/py/plot.py
   trunk/gui/py/yade-multi
   trunk/scripts/multi.py
   trunk/scripts/test/facet-topo.py
Log:
1. Add preliminary gnuplot plots merging facility to yade-multi
2. Fix yade.log module so that it also works without log4cxx (and gives 1 warning)
3. Switch to new syntax in scripts/plot.py


Modified: trunk/gui/py/log.cpp
===================================================================
--- trunk/gui/py/log.cpp	2009-04-08 20:31:20 UTC (rev 1751)
+++ trunk/gui/py/log.cpp	2009-04-09 10:15:52 UTC (rev 1752)
@@ -1,38 +1,48 @@
-
-#ifdef LOG4CXX
-
 #include<boost/python.hpp>
+#include<string>
 #include<yade/lib-base/Logging.hpp>
-#include<log4cxx/logmanager.h>
-#include<string>
 using namespace boost;
-
 enum{ll_TRACE,ll_DEBUG,ll_INFO,ll_WARN,ll_ERROR,ll_FATAL};
 
-void logSetLevel(std::string loggerName,int level){
-	std::string fullName(loggerName.empty()?"yade":("yade."+loggerName));
-	if(!log4cxx::LogManager::exists(fullName)) throw std::invalid_argument("No logger named `"+fullName+"'");
-	log4cxx::LevelPtr l;
-	switch(level){
-		#ifdef LOG4CXX_TRACE
-			case ll_TRACE: l=log4cxx::Level::getTrace(); break;
-			case ll_DEBUG: l=log4cxx::Level::getDebug(); break;
-			case ll_INFO:  l=log4cxx::Level::getInfo(); break;
-			case ll_WARN:  l=log4cxx::Level::getWarn(); break;
-			case ll_ERROR: l=log4cxx::Level::getError(); break;
-			case ll_FATAL: l=log4cxx::Level::getFatal(); break;
-		#else
-			case ll_TRACE: l=log4cxx::Level::DEBUG; break;
-			case ll_DEBUG: l=log4cxx::Level::DEBUG; break;
-			case ll_INFO:  l=log4cxx::Level::INFO; break;
-			case ll_WARN:  l=log4cxx::Level::WARN; break;
-			case ll_ERROR: l=log4cxx::Level::ERROR; break;
-			case ll_FATAL: l=log4cxx::Level::FATAL; break;
-		#endif
-		default: throw std::invalid_argument("Unrecognized logging level "+lexical_cast<std::string>(level));
+#ifdef LOG4CXX
+	#include<log4cxx/logmanager.h>
+
+	void logSetLevel(std::string loggerName,int level){
+		std::string fullName(loggerName.empty()?"yade":("yade."+loggerName));
+		if(!log4cxx::LogManager::exists(fullName)) throw std::invalid_argument("No logger named `"+fullName+"'");
+		log4cxx::LevelPtr l;
+		switch(level){
+			#ifdef LOG4CXX_TRACE
+				case ll_TRACE: l=log4cxx::Level::getTrace(); break;
+				case ll_DEBUG: l=log4cxx::Level::getDebug(); break;
+				case ll_INFO:  l=log4cxx::Level::getInfo(); break;
+				case ll_WARN:  l=log4cxx::Level::getWarn(); break;
+				case ll_ERROR: l=log4cxx::Level::getError(); break;
+				case ll_FATAL: l=log4cxx::Level::getFatal(); break;
+			#else
+				case ll_TRACE: l=log4cxx::Level::DEBUG; break;
+				case ll_DEBUG: l=log4cxx::Level::DEBUG; break;
+				case ll_INFO:  l=log4cxx::Level::INFO; break;
+				case ll_WARN:  l=log4cxx::Level::WARN; break;
+				case ll_ERROR: l=log4cxx::Level::ERROR; break;
+				case ll_FATAL: l=log4cxx::Level::FATAL; break;
+			#endif
+			default: throw std::invalid_argument("Unrecognized logging level "+lexical_cast<std::string>(level));
+		}
+		log4cxx::LogManager::getLogger("yade."+loggerName)->setLevel(l);
 	}
-	log4cxx::LogManager::getLogger("yade."+loggerName)->setLevel(l);
-}
+#else
+	bool warnedOnce=false;
+	void logSetLevel(std::string loggerName, int level){
+		// better somehow python's raise RuntimeWarning, but not sure how to do that from c++
+		// it shouldn't be trapped by boost::python's exception translator, just print warning
+		// Do like this for now.
+		if(!warnedOnce){
+			LOG_WARN("Yade was compiled without log4cxx support. Setting log levels from python will have no effect (warn once).");
+			warnedOnce=true;
+		}
+	}
+#endif
 
 BOOST_PYTHON_MODULE(log){
 	python::def("setLevel",logSetLevel,"Set minimum severity level (constants TRACE,DEBUG,INFO,WARN,ERROR,FATAL) for given logger\nleading 'yade.' will be appended automatically to the logger name; if logger is '', the root logger 'yade' will be operated on.");
@@ -43,5 +53,3 @@
 	python::scope().attr("ERROR")=(int)ll_ERROR;
 	python::scope().attr("FATAL")=(int)ll_FATAL;
 }
-
-#endif

Modified: trunk/gui/py/plot.py
===================================================================
--- trunk/gui/py/plot.py	2009-04-08 20:31:20 UTC (rev 1751)
+++ trunk/gui/py/plot.py	2009-04-09 10:15:52 UTC (rev 1752)
@@ -122,6 +122,8 @@
 		timestamp: append numeric time to the basename
 		varData: whether file to plot will be declared as variable or be in-place in the plot expression
 		comment: a user comment (may be multiline) that will be embedded in the control file
+
+		Returns name fo the gnuplot file created.
 	"""
 	import time,bz2
 	vars=data.keys(); vars.sort()
@@ -153,6 +155,7 @@
 		fPlot.write("plot "+",".join([" %s using %d:%d title '%s(%s)' with lines"%(dataFile,vars.index(p)+1,vars.index(pp[0])+1,pp[0],p) for pp in plots_p])+"\n")
 		i+=1
 	fPlot.close()
+	return baseName+'.gnuplot'
 
 
 	

Modified: trunk/gui/py/yade-multi
===================================================================
--- trunk/gui/py/yade-multi	2009-04-08 20:31:20 UTC (rev 1751)
+++ trunk/gui/py/yade-multi	2009-04-09 10:15:52 UTC (rev 1752)
@@ -3,7 +3,7 @@
 #
 # portions © 2008 Václav Šmilauer <eudoxos@xxxxxxxx>
 
-import os, sys, thread, time
+import os, sys, thread, time,logging
 
 class JobInfo():
 	def __init__(self,num,id,command,log,nSlots):
@@ -67,8 +67,10 @@
 parser.add_option('-l','--lines',dest='lineList',help='Lines of TABLE to use, in the format 2,3-5,8,11-13 (default: all available lines in TABLE)',metavar='LIST')
 parser.add_option('--nice',dest='nice',type='int',help='Nice value of spawned jobs (default: 10)',default=10)
 parser.add_option('--executable',dest='executable',help='Name of the program to run (default: %s)'%sys.argv[0][:-6],default=sys.argv[0][:-6],metavar='FILE') ## strip the '-multi' extension
+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',dest='dryRun',help='Do not actually run (useful for getting gnuplot only, for instance)',default=False)
 opts,args=parser.parse_args()
-logFormat,lineList,maxJobs,nice,executable=opts.logFormat,opts.lineList,opts.maxJobs,opts.nice,opts.executable
+logFormat,lineList,maxJobs,nice,executable,gnuplotOut,dryRun=opts.logFormat,opts.lineList,opts.maxJobs,opts.nice,opts.executable,opts.gnuplotOut,opts.dryRun
 
 if len(args)!=2:
 	#print "Exactly two non-option arguments must be specified -- parameter table and script to be run.\n"
@@ -104,8 +106,8 @@
 		return ret
 	useLines0=numRange2List(lineList)
 	for l in useLines0:
-		if l not in availableLines: print "WARNING: skipping unavailable line %d that was requested from the command line."%l
-		elif l==1: print "WARNING: skipping line 1 that should contain variable labels"
+		if l not in availableLines: logging.warn('skipping unavailable line %d that was requested from the command line.'%l)
+		elif l==1: logging.warn("WARNING: skipping line 1 that should contain variable labels")
 		else: useLines+=[l]
 else: useLines=availableLines
 try:
@@ -131,7 +133,7 @@
 		if head=='!EXEC': executable=values[l][col]
 		if head=='!OMP_NUM_THREADS': nSlots=int(values[l][col])
 		if head[0]=='!': envVars+=['%s=%s'%(head[1:],values[l][col])]
-	if nSlots>maxJobs: print 'WARNING: job #%d wants %d slots but only %d are available'%(i,nSlots,maxJobs)
+	if nSlots>maxJobs: logging.warning('WARNING: job #%d wants %d slots but only %d are available'%(i,nSlots,maxJobs))
 	jobs.append(JobInfo(i,idStrings[l] if idStrings else '#'+str(i),'PARAM_TABLE=%s:%d %s nice -n %d %s -N PythonUI -- -n -x %s > %s 2>&1'%(table,l,' '.join(envVars),nice,executable,simul,logFile),logFile,nSlots))
 
 print "Job summary:"
@@ -139,5 +141,36 @@
 	print '   #%d (%s%s):'%(job.num,job.id,'' if job.nSlots==1 else '/%d'%job.nSlots),job.command
 
 # OK, go now
-runJobs(jobs,maxJobs)
-print 'All jobs finished, bye.'
+if not dryRun: runJobs(jobs,maxJobs)
+
+print 'All jobs finished,',
+if not gnuplotOut:
+	print 'bye.'
+else:
+	print 'assembling gnuplot files…'
+	for job in jobs:
+		for l in file(job.log):
+			if l.startswith('gnuplot '):
+				job.plot=l.split()[1]
+				break
+	preamble,plots='',[]
+	for job in jobs:
+		if not job.plot:
+			# warn here
+			continue
+		for l in file(job.plot):
+			if l.startswith('plot'):
+				# attempt to parse the plot line
+				ll=l.split(' ',1)[1][:-1] # rest of the line, without newline
+				# replace title 'something' with title 'description: something'
+				ll,nn=re.subn(r'title\s+[\'"]([^\'"]*)[\'"]',r'title "'+job.id+r': \1"',ll)
+				if nn==0:
+					logging.error("Plot line in "+job.plot+" not parsed (skipping): "+ll)
+				plots.append(ll)
+				break
+			if not plots: # first plot, copy all preceding lines
+				preamble+=l
+	gp=file(gnuplotOut,'w')
+	gp.write(preamble)
+	gp.write('plot '+','.join(plots))
+	print "Finished writing "+gnuplotOut+", bye."

Modified: trunk/scripts/multi.py
===================================================================
--- trunk/scripts/multi.py	2009-04-08 20:31:20 UTC (rev 1751)
+++ trunk/scripts/multi.py	2009-04-09 10:15:52 UTC (rev 1752)
@@ -8,24 +8,23 @@
 
 o=Omega()
 o.initializers=[
-	MetaEngine('BoundingVolumeMetaEngine',[EngineUnit('InteractingSphere2AABB'),EngineUnit('InteractingFacet2AABB'),EngineUnit('MetaInteractingGeometry2AABB')])
+		BoundingVolumeMetaEngine([InteractingSphere2AABB(),InteractingFacet2AABB(),MetaInteractingGeometry2AABB()])
 	]
 o.engines=[
-	StandAloneEngine('PhysicalActionContainerReseter'),
-	MetaEngine('BoundingVolumeMetaEngine',[
-		EngineUnit('InteractingSphere2AABB'),
-		EngineUnit('InteractingBox2AABB'),
-		EngineUnit('MetaInteractingGeometry2AABB')
+	PhysicalActionContainerReseter(),
+	BoundingVolumeMetaEngine([
+		InteractingSphere2AABB(),
+		InteractingBox2AABB(),
+		MetaInteractingGeometry2AABB()
 	]),
-	StandAloneEngine('PersistentSAPCollider'),
-	MetaEngine('InteractionGeometryMetaEngine',[
-		EngineUnit('InteractingSphere2InteractingSphere4SpheresContactGeometry'),
-		EngineUnit('InteractingBox2InteractingSphere4SpheresContactGeometry')
-	]),
-	MetaEngine('InteractionPhysicsMetaEngine',[EngineUnit('SimpleElasticRelationships')]),
-	StandAloneEngine('ElasticContactLaw'),
-	DeusExMachina('GravityEngine',{'gravity':[0,0,gravity]}), ## here we use the 'gravity' parameter
-	DeusExMachina('NewtonsDampedLaw',{'damping':0.4})
+	PersistentSAPCollider(),
+	InteractionDispatchers(
+		[InteractingSphere2InteractingSphere4SpheresContactGeometry(),InteractingBox2InteractingSphere4SpheresContactGeometry()],
+		[SimpleElasticRelationships(),],
+		[ef2_Spheres_Elastic_ElasticLaw(),]
+	)
+	GravityEngine(gravity=(0,0,gravity)), ## here we use the 'gravity' parameter
+	NewtonsDampedLaw(damping=0.4)
 ]
 o.bodies.append(utils.box([0,50,0],extents=[1,50,1],dynamic=False,color=[1,0,0],young=30e9,poisson=.3,density=density)) ## here we use the density parameter
 o.bodies.append(utils.sphere([0,0,10],1,color=[0,1,0],young=30e9,poisson=.3,density=density)) ## here again

Modified: trunk/scripts/test/facet-topo.py
===================================================================
--- trunk/scripts/test/facet-topo.py	2009-04-08 20:31:20 UTC (rev 1751)
+++ trunk/scripts/test/facet-topo.py	2009-04-09 10:15:52 UTC (rev 1752)
@@ -20,5 +20,5 @@
 		utils.facet([(1,1,0),(1,0,0),(0,1,0)]),
 	])
 	O.step()
-	#assert(O.bodies[0].phys['edgeAdjIds'][1]==1 and O.bodies[1].phys['edgeAdjIds'][0]==1)
+	assert(O.bodies[0].phys['edgeAdjIds'][1]==1 and O.bodies[1].phys['edgeAdjIds'][0]==1)
 	assert(topo['commonEdgesFound']==1)