yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #05586
[Branch ~yade-dev/yade/trunk] Rev 2416: 1. Add foce, torque etc display in the body tab of the inspector
------------------------------------------------------------
revno: 2416
committer: Václav Šmilauer <eudoxos@xxxxxxxx>
branch nick: trunk
timestamp: Fri 2010-08-27 10:28:50 +0200
message:
1. Add foce, torque etc display in the body tab of the inspector
2. Make force, torque etc access from python not require thread synchronization (sums up threads on demand)
modified:
core/ForceContainer.hpp
gui/qt4/Inspector.py
py/wrapper/yadeWrapper.cpp
--
lp:yade
https://code.launchpad.net/~yade-dev/yade/trunk
Your team Yade developers is subscribed to branch lp:yade.
To unsubscribe from this branch go to https://code.launchpad.net/~yade-dev/yade/trunk/+edit-subscription
=== modified file 'core/ForceContainer.hpp'
--- core/ForceContainer.hpp 2010-08-26 16:56:07 +0000
+++ core/ForceContainer.hpp 2010-08-27 08:28:50 +0000
@@ -64,11 +64,13 @@
inline void ensureSynced(){ if(!synced) throw runtime_error("ForceContainer not thread-synchronized; call sync() first!"); }
- /*! Function to allow friend classes to get force even if not synced.
- * Dangerous! The caller must know what it is doing! (i.e. don't read after write
- * for a particular body id. */
- const Vector3r& getForceUnsynced (Body::id_t id){ensureSize(id); return _force[id];}
- const Vector3r& getTorqueUnsynced(Body::id_t id){ensureSize(id); return _force[id];}
+ #if 0
+ /*! Function to allow friend classes to get force even if not synced.
+ * Dangerous! The caller must know what it is doing! (i.e. don't read after write
+ * for a particular body id. */
+ const Vector3r& getForceUnsynced (Body::id_t id){ensureSize(id); return _force[id];}
+ const Vector3r& getTorqueUnsynced(Body::id_t id){ensureSize(id); return _force[id];}
+ #endif
// dummy function to avoid template resolution failure
friend class boost::serialization::access; template<class ArchiveT> void serialize(ArchiveT & ar, unsigned int version){}
public:
@@ -80,7 +82,6 @@
}
}
- /* To be benchmarked: sum thread data in getForce/getTorque upon request for each body individually instead of by the sync() function globally */
const Vector3r& getForce(Body::id_t id) { ensureSize(id); ensureSynced(); return _force[id]; }
void addForce(Body::id_t id, const Vector3r& f){ ensureSize(id); synced=false; _forceData[omp_get_thread_num()][id]+=f;}
const Vector3r& getTorque(Body::id_t id) { ensureSize(id); ensureSynced(); return _torque[id]; }
@@ -89,6 +90,13 @@
void addMove(Body::id_t id, const Vector3r& m) { ensureSize(id); synced=false; moveRotUsed=true; _moveData[omp_get_thread_num()][id]+=m;}
const Vector3r& getRot(Body::id_t id) { ensureSize(id); ensureSynced(); return _rot[id]; }
void addRot(Body::id_t id, const Vector3r& r) { ensureSize(id); synced=false; moveRotUsed=true; _rotData[omp_get_thread_num()][id]+=r;}
+ /* To be benchmarked: sum thread data in getForce/getTorque upon request for each body individually instead of by the sync() function globally */
+ // this function is used from python so that running simulation is not slowed down by sync'ing on occasions
+ // since Vector3r writes are not atomic, it might (rarely) return wrong value, if the computation is running meanwhile
+ Vector3r getForceSingle (Body::id_t id){ ensureSize(id); Vector3r ret(Vector3r::Zero()); for(int t=0; t<nThreads; t++){ ret+=_forceData [t][id]; } return ret; }
+ Vector3r getTorqueSingle(Body::id_t id){ ensureSize(id); Vector3r ret(Vector3r::Zero()); for(int t=0; t<nThreads; t++){ ret+=_torqueData[t][id]; } return ret; }
+ Vector3r getMoveSingle (Body::id_t id){ ensureSize(id); Vector3r ret(Vector3r::Zero()); for(int t=0; t<nThreads; t++){ ret+=_moveData [t][id]; } return ret; }
+ Vector3r getRotSingle (Body::id_t id){ ensureSize(id); Vector3r ret(Vector3r::Zero()); for(int t=0; t<nThreads; t++){ ret+=_rotData [t][id]; } return ret; }
/* Sum contributions from all threads, save to _force&_torque.
* Locks globalMutex, since one thread modifies common data (_force&_torque).
@@ -164,8 +172,10 @@
std::vector<Vector3r> _rot;
size_t size;
inline void ensureSize(Body::id_t id){ if(size<=(size_t)id) resize(min((size_t)1.5*(id+100),(size_t)(id+2000)));}
- const Vector3r& getForceUnsynced (Body::id_t id){ return getForce(id);}
- const Vector3r& getTorqueUnsynced(Body::id_t id){ return getForce(id);}
+ #if 0
+ const Vector3r& getForceUnsynced (Body::id_t id){ return getForce(id);}
+ const Vector3r& getTorqueUnsynced(Body::id_t id){ return getForce(id);}
+ #endif
bool moveRotUsed;
// dummy function to avoid template resolution failure
friend class boost::serialization::access; template<class ArchiveT> void serialize(ArchiveT & ar, unsigned int version){}
@@ -179,6 +189,12 @@
void addMove(Body::id_t id,const Vector3r& f){ensureSize(id); moveRotUsed=true; _move[id]+=f;}
const Vector3r& getRot(Body::id_t id){ensureSize(id); return _rot[id];}
void addRot(Body::id_t id,const Vector3r& f){ensureSize(id); moveRotUsed=true; _rot[id]+=f;}
+ // single getters do the same as globally synced ones in the non-parallel flavor
+ const Vector3r& getForceSingle (Body::id_t id){ ensureSize(id); return _force [id]; }
+ const Vector3r& getTorqueSingle(Body::id_t id){ ensureSize(id); return _torque[id]; }
+ const Vector3r& getMoveSingle (Body::id_t id){ ensureSize(id); return _move [id]; }
+ const Vector3r& getRotSingle (Body::id_t id){ ensureSize(id); return _rot [id]; }
+
//! Set all forces to zero
void reset(){
memset(&_force [0],0,sizeof(Vector3r)*size);
=== modified file 'gui/qt4/Inspector.py'
--- gui/qt4/Inspector.py 2010-08-13 15:18:16 +0000
+++ gui/qt4/Inspector.py 2010-08-27 08:28:50 +0000
@@ -79,19 +79,30 @@
self.intrWithCombo=QComboBox(self);
self.gotoBodyButton=QPushButton(u'â #',self)
self.gotoIntrButton=QPushButton(u'â #+#',self)
- topBoxWidget=QWidget(self)
- topBox=QHBoxLayout(topBoxWidget)
- hashLabel=QLabel('#',self); hashLabel.setFixedWidth(10)
+ # id selector
+ topBoxWidget=QWidget(self); topBox=QHBoxLayout(topBoxWidget); topBox.setMargin(0); #topBox.setSpacing(0);
+ hashLabel=QLabel('#',self); hashLabel.setFixedWidth(8)
topBox.addWidget(hashLabel)
topBox.addWidget(self.bodyIdBox)
- self.plusLabel=QLabel('+',self)
- topBox.addWidget(self.plusLabel)
+ self.plusLabel=QLabel('+',self); topBox.addWidget(self.plusLabel)
+ hashLabel2=QLabel('#',self); hashLabel2.setFixedWidth(8); topBox.addWidget(hashLabel2)
topBox.addWidget(self.intrWithCombo)
+ topBox.addStretch()
topBox.addWidget(self.gotoBodyButton)
topBox.addWidget(self.gotoIntrButton)
topBoxWidget.setLayout(topBox)
+ # forces display
+ forcesWidget=QFrame(self); forcesWidget.setFrameShape(QFrame.Box); self.forceGrid=QGridLayout(forcesWidget);
+ self.forceGrid.setVerticalSpacing(0); self.forceGrid.setHorizontalSpacing(9); self.forceGrid.setMargin(4);
+ for i,j in itertools.product((0,1,2,3),(-1,0,1,2)):
+ lab=QLabel('<small>'+('force','torque','move','rot')[i]+'</small>' if j==-1 else ''); self.forceGrid.addWidget(lab,i,j+1);
+ if j>=0: lab.setAlignment(Qt.AlignRight)
+ if i>1: lab.hide() # do not show forced moves and rotations by default (they will appear if non-zero)
+ self.showMovRot=False
+ #
self.grid=QGridLayout(self); self.grid.setSpacing(0); self.grid.setMargin(0)
self.grid.addWidget(topBoxWidget)
+ self.grid.addWidget(forcesWidget)
self.scroll=QScrollArea(self)
self.scroll.setWidgetResizable(True)
self.grid.addWidget(self.scroll)
@@ -106,6 +117,20 @@
self.intrWithCombo.setMinimumWidth(80)
self.setWindowTitle('Body #%d'%self.bodyId)
self.gotoBodySlot()
+ def displayForces(self):
+ if self.bodyId<0: return
+ try:
+ val=[O.forces.f(self.bodyId),O.forces.t(self.bodyId),O.forces.move(self.bodyId),O.forces.rot(self.bodyId)]
+ hasMovRot=(val[2]!=Vector3.Zero or val[3]!=Vector3.Zero)
+ if hasMovRot!=self.showMovRot:
+ for i,j in itertools.product((2,3),(-1,0,1,2)):
+ if hasMovRot: self.forceGrid.itemAtPosition(i,j+1).widget().show()
+ else: self.forceGrid.itemAtPosition(i,j+1).widget().hide()
+ self.showMovRot=hasMovRot
+ rows=((0,1,2,3) if hasMovRot else (0,1))
+ for i,j in itertools.product(rows,(0,1,2)):
+ self.forceGrid.itemAtPosition(i,j+1).widget().setText('<small>'+str(val[i][j])+'</small>')
+ except IndexError:pass
def tryShowBody(self):
try:
b=O.bodies[self.bodyId]
@@ -169,6 +194,7 @@
self.gotoBodyButton.setEnabled(True); self.gotoIntrButton.setEnabled(True)
self.gotoBodyButton.setText(u'â %s'%other)
self.gotoIntrButton.setText(u'â %s + %s'%(meLabel,other))
+ self.displayForces()
class InteractionInspector(QWidget):
def __init__(self,ids=None,parent=None,bodyLinkCallback=None):
=== modified file 'py/wrapper/yadeWrapper.cpp'
--- py/wrapper/yadeWrapper.cpp 2010-08-26 16:56:07 +0000
+++ py/wrapper/yadeWrapper.cpp 2010-08-27 08:28:50 +0000
@@ -219,10 +219,10 @@
public:
pyForceContainer(shared_ptr<Scene> _scene): scene(_scene) { }
void checkId(long id){ if(id<0 || (size_t)id>=scene->bodies->size()){ PyErr_SetString(PyExc_IndexError, "Body id out of range."); python::throw_error_already_set(); /* never reached */ throw; } }
- Vector3r force_get(long id){ checkId(id); scene->forces.sync(); return scene->forces.getForce(id); }
- Vector3r torque_get(long id){ checkId(id); scene->forces.sync(); return scene->forces.getTorque(id); }
- Vector3r move_get(long id){ checkId(id); scene->forces.sync(); return scene->forces.getMove(id); }
- Vector3r rot_get(long id){ checkId(id); scene->forces.sync(); return scene->forces.getRot(id); }
+ Vector3r force_get(long id){ checkId(id); return scene->forces.getForceSingle(id); /* scene->forces.sync(); return scene->forces.getForce(id); */}
+ Vector3r torque_get(long id){ checkId(id); return scene->forces.getTorqueSingle(id); }
+ Vector3r move_get(long id){ checkId(id); return scene->forces.getMoveSingle(id); }
+ Vector3r rot_get(long id){ checkId(id); return scene->forces.getRotSingle(id); }
void force_add(long id, const Vector3r& f){ checkId(id); scene->forces.addForce (id,f); }
void torque_add(long id, const Vector3r& t){ checkId(id); scene->forces.addTorque(id,t);}
void move_add(long id, const Vector3r& t){ checkId(id); scene->forces.addMove(id,t);}