Author: eudoxos
Date: 2009-04-23 15:20:50 +0200 (Thu, 23 Apr 2009)
New Revision: 1758
Modified:
trunk/extra/usct/UniaxialStrainControlledTest.cpp
trunk/extra/usct/UniaxialStrainControlledTest.hpp
trunk/gui/py/utils.py
trunk/gui/py/yade-multi
Log:
1. Remove cruft from UniaxialStrainer, add the ability to set initial
velocities to suppress inertia at the simulation beginning
2. Jobs in yade-multi can be automatically named after variables suffixed with !
3. yade-multi now shows and updates automatically some statistic on
localhost:9080 using http
Modified: trunk/extra/usct/UniaxialStrainControlledTest.cpp
===================================================================
--- trunk/extra/usct/UniaxialStrainControlledTest.cpp 2009-04-22 06:57:45 UTC
(rev 1757)
+++ trunk/extra/usct/UniaxialStrainControlledTest.cpp 2009-04-23 13:20:50 UTC
(rev 1758)
@@ -20,7 +20,7 @@
assert(posIds.size()>0);
assert(negIds.size()>0);
posCoords.clear(); negCoords.clear();
- FOREACH(body_id_t id,posIds){ const shared_ptr<Body>& b=Body::byId(id);
posCoords.push_back(b->physicalParameters->se3.position[axis]);
+ FOREACH(body_id_t id,posIds){ const shared_ptr<Body>&
b=Body::byId(id,rootBody);
posCoords.push_back(b->physicalParameters->se3.position[axis]);
if(blockDisplacements && blockRotations) b->isDynamic=false;
else{
shared_ptr<PhysicalParameters>
&pp=b->physicalParameters;
@@ -28,7 +28,7 @@
if(blockRotations)
pp->blockedDOFs|=PhysicalParameters::DOF_RXRYRZ;
}
}
- FOREACH(body_id_t id,negIds){ const shared_ptr<Body>& b=Body::byId(id);
negCoords.push_back(b->physicalParameters->se3.position[axis]);
+ FOREACH(body_id_t id,negIds){ const shared_ptr<Body>&
b=Body::byId(id,rootBody);
negCoords.push_back(b->physicalParameters->se3.position[axis]);
if(blockDisplacements && blockRotations) b->isDynamic=false;
else{
shared_ptr<PhysicalParameters>
&pp=b->physicalParameters;
@@ -49,11 +49,43 @@
assert(originalLength>0 && !isnan(originalLength));
assert(!isnan(strainRate) || !isnan(absSpeed));
- if(strainRate==0){ strainRate=absSpeed/originalLength;
LOG_INFO("Computed new strainRate "<<strainRate); }
+ if(!isnan(std::numeric_limits<Real>::quiet_NaN())){ LOG_FATAL("NaN's
are not properly supported (compiled, with -ffast-math?), which is required.");
throw; }
- initAccelTime_s=initAccelTime>=0 ? initAccelTime :
Omega::instance().getTimeStep()*(-initAccelTime);
- LOG_INFO("Strain speed will be "<<absSpeed<<", strain rate
"<<strainRate<<", will be reached after "<<initAccelTime_s<<"s
("<<initAccelTime_s/Omega::instance().getTimeStep()<<" steps).");
+ if(isnan(strainRate)){ strainRate=absSpeed/originalLength;
LOG_INFO("Computed new strainRate "<<strainRate); }
+ else {absSpeed=strainRate*originalLength;}
+ if(!setSpeeds){
+ initAccelTime_s=initAccelTime>=0 ? initAccelTime :
Omega::instance().getTimeStep()*(-initAccelTime);
+ LOG_INFO("Strain speed will be "<<absSpeed<<", strain rate
"<<strainRate<<", will be reached after "<<initAccelTime_s<<"s
("<<initAccelTime_s/Omega::instance().getTimeStep()<<" steps).");
+ } else {
+ /* set speed such that it is linear on the strained axis;
transversal speed is not set, which can perhaps create some problems.
+ Note: all bodies in the simulation will have their
speed set, since there is no way to tell which ones are part of the specimen
+ and which are not.
+
+ Speeds will be linearly interpolated beween axis
positions p0,p1 and velocities v0,v1.
+ */
+ initAccelTime_s=0;
+ LOG_INFO("Strain speed will be "<<absSpeed<<", strain rate
"<<strainRate<<"; velocities will be set directly at the beginning.");
+ Real p0=axisCoord(negIds[0]), p1=axisCoord(posIds[0]); // limit
positions
+ Real v0,v1; // speeds at p0, p1
+ switch(asymmetry){
+ case -1: v0=-absSpeed; v1=0; break;
+ case 0: v0=-absSpeed/2; v1=absSpeed/2; break;
+ case 1: v0=0; v1=absSpeed; break;
+ default: LOG_FATAL("Unknown asymmetry value
"<<asymmetry<<" (should be -1,0,1)"); throw;
+ }
+ assert(p1>p0);
+ FOREACH(const shared_ptr<Body>& b, *rootBody->bodies){
+ // skip bodies on the boundary, since those will have
their positions updated directly
+
if(std::find(posIds.begin(),posIds.end(),b->id)!=posIds.end() ||
std::find(negIds.begin(),negIds.end(),b->id)!=negIds.end()) { continue; }
+ Real p=axisCoord(b->id);
+ Real pNormalized=(p-p0)/(p1-p0);
+
YADE_CAST<ParticleParameters*>(b->physicalParameters.get())->velocity[axis]=pNormalized*(v1-v0)+v0;
+ }
+ }
+
stressUpdateInterval=max(1,(int)(2e-5/(abs(strainRate)*Omega::instance().getTimeStep())));
+ LOG_INFO("Stress will be updated every "<<stressUpdateInterval<<"
steps.");
+
/* if we have default (<0) crossSectionArea, try to get it from root's
AABB;
* this will not work if there are foreign bodies in the simulation,
* in which case you must give the value yourself as engine attribute.
@@ -75,13 +107,10 @@
}
}
assert(crossSectionArea>0);
- prepareRecStream();
-#if 0
- setupTransStrainSensors();
-#endif
}
-void UniaxialStrainer::applyCondition(MetaBody* rootBody){
+void UniaxialStrainer::applyCondition(MetaBody* _rootBody){
+ rootBody=_rootBody;
if(needsInit) init();
// postconditions for initParams
assert(posIds.size()==posCoords.size() &&
negIds.size()==negCoords.size() && originalLength>0 && crossSectionArea>0);
@@ -117,19 +146,18 @@
Real axialLength=axisCoord(posIds[0])-axisCoord(negIds[0]);
strain=axialLength/originalLength-1;
- if(Omega::instance().getCurrentIteration()%400==0)
TRVAR5(dAX,axialLength,originalLength,currentStrainRate,strain);
// reverse if we're over the limit strain
if(notYetReversed && limitStrain!=0 && ((currentStrainRate>0 &&
strain>limitStrain) || (currentStrainRate<0 && strain<limitStrain))) {
currentStrainRate*=-1; notYetReversed=false; LOG_INFO("Reversed strain rate to
"<<currentStrainRate); }
- if(Omega::instance().getCurrentIteration()%10==0) {
- computeAxialForce(rootBody);
+ // update forces and stresses
+ if(Omega::instance().getCurrentIteration()%stressUpdateInterval==0) {
+ computeAxialForce();
avgStress=(sumPosForces+sumNegForces)/(2*crossSectionArea); //
average nominal stress
- if(!recordFile.empty() && recStream.good())
recStream<<Omega::instance().getCurrentIteration()<<" "<<strain<<"
"<<avgStress<<endl; // <<" "<<avgTransStrain<<endl;
}
}
-void UniaxialStrainer::computeAxialForce(MetaBody* rootBody){
+void UniaxialStrainer::computeAxialForce(){
sumPosForces=sumNegForces=0;
rootBody->bex.sync();
FOREACH(body_id_t id, negIds)
sumNegForces+=rootBody->bex.getForce(id)[axis];
@@ -220,7 +248,6 @@
#include<yade/pkg-common/LeapFrogPositionIntegrator.hpp>
#include<yade/pkg-common/LeapFrogOrientationIntegrator.hpp>
#include<yade/pkg-common/PersistentSAPCollider.hpp>
-#include<yade/pkg-dem/PositionOrientationRecorder.hpp>
#include<yade/pkg-dem/GlobalStiffnessTimeStepper.hpp>
#include<yade/pkg-common/PhysicalActionDamper.hpp>
#include<yade/pkg-common/CundallNonViscousDamping.hpp>
Modified: trunk/extra/usct/UniaxialStrainControlledTest.hpp
===================================================================
--- trunk/extra/usct/UniaxialStrainControlledTest.hpp 2009-04-22 06:57:45 UTC
(rev 1757)
+++ trunk/extra/usct/UniaxialStrainControlledTest.hpp 2009-04-23 13:20:50 UTC
(rev 1758)
@@ -46,13 +46,12 @@
*/
class UniaxialStrainer: public DeusExMachina {
private:
+ MetaBody* rootBody;
bool idInVector(body_id_t id, const vector<body_id_t>&
V){for(size_t i=0; i<V.size(); i++){ if(V[i]==id) return true; } return false;
} // unused now
- void computeAxialForce(MetaBody* rootBody);
+ void computeAxialForce();
- ofstream recStream;
- string recordFile;
bool needsInit;
- Real& axisCoord(body_id_t id){ return
Body::byId(id)->physicalParameters->se3.position[axis]; };
+ Real& axisCoord(body_id_t id){ return
Body::byId(id,rootBody)->physicalParameters->se3.position[axis]; };
void init();
public:
virtual bool isActivated(){return active;}
@@ -71,6 +70,7 @@
Real sumPosForces,sumNegForces;
//! crossSection perpendicular to he strained axis, computed
from AABB of MetaBody
Real crossSectionArea; //! Apply strain along x (0), y
(1) or z(2) axis
+ //! The axis which is strained (0,1,2 for x,y,z)
int axis;
//! If 0, straining is symmetric for negIds and posIds; for 1
(or -1), only posIds are strained and negIds don't move (or vice versa)
int asymmetry;
@@ -84,6 +84,10 @@
long idleIterations;
//! Time for strain reaching the requested value (linear
interpolation). If negative, the time is dt*(-initAccelTime), where dt is the
timestep at the first iteration.
Real initAccelTime, initAccelTime_s /* value always in s,
computed from initAccelTime */;
+ //! should we set speeds at the beginning directly, instead of
increasing strain rate progressively?
+ bool setSpeeds;
+ //! how often to update forces (initialized automatically)
+ int stressUpdateInterval;
/** bodies on which straining will be applied (on the positive
and negative side of axis) */
vector<body_id_t> posIds, negIds;
@@ -110,7 +114,7 @@
Real strain, avgStress;
virtual void applyCondition(MetaBody* rootBody);
- UniaxialStrainer(){axis=2; asymmetry=0; currentStrainRate=0;
originalLength=-1; limitStrain=0; notYetReversed=true; crossSectionArea=-1;
needsInit=true; /* sensorsPusher=shared_ptr<UniaxialStrainSensorPusher>(); */
recordFile=""; strain=avgStress=/*avgTransStrain=*/0; blockRotations=false;
blockDisplacements=false; strainRate=0;
absSpeed=stopStrain=numeric_limits<Real>::quiet_NaN(); active=true;
idleIterations=0; initAccelTime=-200;};
+ UniaxialStrainer(){axis=2; asymmetry=0; currentStrainRate=0;
originalLength=-1; limitStrain=0; notYetReversed=true; crossSectionArea=-1;
needsInit=true; strain=avgStress=0; blockRotations=false;
blockDisplacements=false; setSpeeds=false;
strainRate=absSpeed=stopStrain=numeric_limits<Real>::quiet_NaN(); active=true;
idleIterations=0; initAccelTime=-200;};
virtual ~UniaxialStrainer(){};
REGISTER_ATTRIBUTES(DeusExMachina,
(strainRate)
@@ -128,14 +132,12 @@
(limitStrain)
(notYetReversed)
(crossSectionArea)
- (recordFile)
(strain)
(avgStress)
(blockDisplacements)
(blockRotations)
+ (setSpeeds)
);
- void prepareRecStream(void){ if(!recordFile.empty())
recStream.open(recordFile.c_str()); }
- void postProcessAttributes(bool deserializing){
if(deserializing) prepareRecStream(); }
REGISTER_CLASS_AND_BASE(UniaxialStrainer,DeusExMachina);
DECLARE_LOGGER;
};
Modified: trunk/gui/py/utils.py
===================================================================
--- trunk/gui/py/utils.py 2009-04-22 06:57:45 UTC (rev 1757)
+++ trunk/gui/py/utils.py 2009-04-23 13:20:50 UTC (rev 1758)
@@ -347,21 +347,30 @@
o.tags['line']='l!'
else:
if not tableFileLine: tableFileLine=os.environ['PARAM_TABLE']
- tableFile,tableLine=tableFileLine.split(':')
+ env=tableFileLine.split(':')
+ tableDesc=None
+ tableFile,tableLine=env[0],env[1]
+ if len(env)>2: tableDesc=env[3]
o.tags['line']='l'+tableLine
ll=[l.split('#')[0] for l in ['']+open(tableFile).readlines()];
names=ll[1].split(); values=ll[int(tableLine)].split()
assert(len(names)==len(values))
+ if 'description' in names:
O.tags['description']=values[names.index('description')]
+ else:
+ bangCols=[i for i,h in enumerate(names) if h[-1]=='!']
+ if len(bangCols)==0: bangCols=range(len(headings))
+ for i in range(len(names)):
+ if names[i][-1]=='!': names[i]=names[i][:-1] #
strip trailing !
+ O.tags['description']=','.join(
names[col]+'='+('%g'%values[col] if isinstance(values[col],float) else
str(values[col])) for col in bangCols)
for i in range(len(names)):
- if names[i]=='description':
o.tags['description']=values[i]
- else:
- if names[i] not in kw.keys():
- if (not unknownOk) and
names[i][0]!='!': raise NameError("Parameter `%s' has no default value
assigned"%names[i])
- else: kw.pop(names[i])
- if names[i][0]!='!':
-
exec('__builtin__.%s=%s'%(names[i],values[i]));
tagsParams+=['%s=%s'%(names[i],values[i])]; dictParams[names[i]]=values[i]
+ if names[i]=='description': continue
+ if names[i] not in kw.keys():
+ if (not unknownOk) and names[i][0]!='!': raise
NameError("Parameter `%s' has no default value assigned"%names[i])
+ else: kw.pop(names[i])
+ if names[i][0]!='!':
+ exec('%s=%s'%(names[i],values[i])) in
__builtins__; tagsParams+=['%s=%s'%(names[i],values[i])];
dictParams[names[i]]=values[i]
defaults=[]
for k in kw.keys():
- exec("__builtin__.%s=%s"%(k,repr(kw[k])))
+ exec("%s=%s"%(k,repr(kw[k]))) in __builtins__
defaults+=["%s=%s"%(k,kw[k])]; dictDefaults[k]=kw[k]
o.tags['defaultParams']=",".join(defaults)
o.tags['params']=",".join(tagsParams)
Modified: trunk/gui/py/yade-multi
===================================================================
--- trunk/gui/py/yade-multi 2009-04-22 06:57:45 UTC (rev 1757)
+++ trunk/gui/py/yade-multi 2009-04-23 13:20:50 UTC (rev 1758)
@@ -23,9 +23,48 @@
finished: %s
"""%(self.id,self.exitStatus,'OK' if self.exitStatus==0 else
'FAILED',self.duration,self.command,time.asctime(time.localtime(self.started)),time.asctime(time.localtime(self.finished))));
log.close()
+ def t2hhmmss(self,dt): return
'%02d:%02d:%02d'%(dt//3600,(dt%3600)//60,(dt%60))
+ def htmlStats(self):
+ ret='<tr>'
+ ret+='<td>%s</td>'%self.id
+ if self.status=='PENDING': ret+='<td
bgcolor="grey">(pending)</td>'
+ elif self.status=='RUNNING': ret+='<td
bgcolor="yellow">%s</td>'%self.t2hhmmss(time.time()-self.started)
+ elif self.status=='DONE': ret+='<td
bgcolor="%s">%s</td>'%('green' if self.exitStatus==0 else 'red',self.duration)
+ ret+='<td>%s</td>'%self.command
+ ret+='<td>%d</td>'%self.nSlots
+ ret+='</tr>'
+ return ret
+def globalHtmlStats():
+ ret='<h3>Jobs</h3>'
+ nFailed=len([j for j in jobs if j.status=='DONE' and j.exitStatus!=0])
+ ret+='<p><b>%d</b> total, <b>%d</b> <span
style="background-color:yellow">running</span>, <b>%d</b> <span
style="background-color:green">done</span>%s</p>'%(len(jobs),len([j for j in
jobs if j.status=='RUNNING']), len([j for j in jobs if j.status=='DONE']),'
(<b>%d <span style="background-color:red"><b>failed</b></span>)'%nFailed if
nFailed>0 else '')
+ return ret
+from BaseHTTPServer import BaseHTTPRequestHandler,HTTPServer
+import socket
+class HttpStatsServer(BaseHTTPRequestHandler):
+ def do_GET(self):
+ self.send_response(200)
+ self.send_header('Content-type','text/html')
+ self.send_header('refresh','5')
+ self.end_headers()
+ self.wfile.write('<HTML><TITLE>Yade-multi
overview</TITLE><BODY>')
+ self.wfile.write(globalHtmlStats())
+ self.wfile.write('<TABLE
border=1><tr><th>id</th><th>status</th><th>command</th><th>slots</th></tr>')
+ for j in jobs:
+ self.wfile.write(j.htmlStats())
+ self.wfile.write('</TABLE></BODY></HTML>')
+ return
+ def log_request(self,req): pass
+def runHttpStatsServer():
+ try:
+ server=HTTPServer(('',9080),HttpStatsServer)
+ import thread; thread.start_new_thread(server.serve_forever,())
+ except socket.error:
+ print "WARN: Port 9080 occupied, not starting HTTP stats server"
+
def runJob(job):
job.status='RUNNING'
job.started=time.time();
@@ -33,7 +72,7 @@
job.exitStatus=os.system(job.command)
job.finished=time.time()
dt=job.finished-job.started;
- job.duration='%02d:%02d:%02d'%(dt//3600,(dt%3600)//60,(dt%60))
+ job.duration=job.t2hhmmss(dt)
strStatus='done ' if job.exitStatus==0 else 'FAILED '
job.status='DONE'
print "#%d (%s%s) %s (exit status %d), duration %s, log
%s"%(job.num,job.id,'' if job.nSlots==1 else
'/%d'%job.nSlots,strStatus,job.exitStatus,job.duration,job.log)
@@ -117,8 +156,20 @@
print "Will use lines ",', '.join([str(i)+' (%s)'%idStrings[i] for i in
useLines])+'.'
#print idStrings
except ValueError:
- idColumn=None
- idStrings=None
+ # try to get idStrings from columns with trailing !
+ bangCols=[i for i,h in enumerate(headings) if h[-1]=='!']
+ if len(bangCols)==0:
+ print 'WARN: no headings with trailing !, will use all of them
for description'
+ bangCols=range(len(headings))
+ for i in range(len(headings)):
+ if headings[i][-1]=='!': headings[i]=headings[i][:-1]
+ idStrings={}
+ for i in useLines:
+ newIdBase=','.join( headings[col]+'='+('%g'%values[i][col] if
isinstance(values[i][col],float) else str(values[i][col])) for col in bangCols)
+ newId=newIdBase; j=1
+ while newId in idStrings.values():
+ newId=newIdBase+'_%d_'%j; j+=1
+ idStrings[i]=newId
print "Will use lines ",', '.join([str(i) for i in useLines])+'.'
@@ -140,6 +191,8 @@
for job in jobs:
print ' #%d (%s%s):'%(job.num,job.id,'' if job.nSlots==1 else
'/%d'%job.nSlots),job.command
+runHttpStatsServer()
+
# OK, go now
if not dryRun: runJobs(jobs,maxJobs)
_______________________________________________
Mailing list: https://launchpad.net/~yade-dev
Post to : [email protected]
Unsubscribe : https://launchpad.net/~yade-dev
More help : https://help.launchpad.net/ListHelp
_______________________________________________
yade-dev mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/yade-dev