yade-dev team mailing list archive
-
yade-dev team
-
Mailing list archive
-
Message #01190
[svn] r1750 - in trunk: lib/QGLViewer/VRender pkg/common/DataClass/InteractingGeometry pkg/common/Engine/StandAloneEngine pkg/dem/Engine/StandAloneEngine scripts/test
Author: eudoxos
Date: 2009-04-08 22:27:04 +0200 (Wed, 08 Apr 2009)
New Revision: 1750
Added:
trunk/scripts/test/facet-topo.py
Modified:
trunk/lib/QGLViewer/VRender/BSPSortMethod.cpp
trunk/lib/QGLViewer/VRender/Exporter.cpp
trunk/lib/QGLViewer/VRender/FIGExporter.cpp
trunk/pkg/common/DataClass/InteractingGeometry/InteractingFacet.cpp
trunk/pkg/common/DataClass/InteractingGeometry/InteractingFacet.hpp
trunk/pkg/common/Engine/StandAloneEngine/PersistentSAPCollider.cpp
trunk/pkg/common/Engine/StandAloneEngine/PersistentSAPCollider.hpp
trunk/pkg/dem/Engine/StandAloneEngine/FacetTopologyAnalyzer.cpp
trunk/pkg/dem/Engine/StandAloneEngine/FacetTopologyAnalyzer.hpp
Log:
1. Parallelize initial bound filling in PersistentSAPCollider. Gives almost 3x speedup for the first step.
2. Fix missing headers so that it compiles with g++-4.4 (in QGLViewer)
3. FacetTopologyAnalyzer works (not tested extensively), questions of where to put topology data for InteractingFacet (will be raised on yade-dev)
4. Test script for FacetTopologyAnalyzer.
Modified: trunk/lib/QGLViewer/VRender/BSPSortMethod.cpp
===================================================================
--- trunk/lib/QGLViewer/VRender/BSPSortMethod.cpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/lib/QGLViewer/VRender/BSPSortMethod.cpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -49,6 +49,7 @@
#include "Primitive.h"
#include "SortMethod.h"
#include "math.h" // fabs
+#include <cstdio>
using namespace vrender ;
using namespace std;
Modified: trunk/lib/QGLViewer/VRender/Exporter.cpp
===================================================================
--- trunk/lib/QGLViewer/VRender/Exporter.cpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/lib/QGLViewer/VRender/Exporter.cpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -48,6 +48,7 @@
#include <stdexcept>
#include "VRender.h"
#include "Exporter.h"
+#include <cstdio>
using namespace vrender ;
using namespace std ;
Modified: trunk/lib/QGLViewer/VRender/FIGExporter.cpp
===================================================================
--- trunk/lib/QGLViewer/VRender/FIGExporter.cpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/lib/QGLViewer/VRender/FIGExporter.cpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -47,6 +47,7 @@
#include "Exporter.h"
#include "math.h"
+#include <cstdio>
using namespace vrender ;
using namespace std ;
Modified: trunk/pkg/common/DataClass/InteractingGeometry/InteractingFacet.cpp
===================================================================
--- trunk/pkg/common/DataClass/InteractingGeometry/InteractingFacet.cpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/pkg/common/DataClass/InteractingGeometry/InteractingFacet.cpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -9,7 +9,10 @@
InteractingFacet::InteractingFacet() : InteractingGeometry()
{
- createIndex();
+ createIndex();
+ #ifdef FACET_TOPO
+ edgeAdjIds.resize(3,Body::ID_NONE);
+ #endif
}
InteractingFacet::~InteractingFacet()
@@ -20,6 +23,9 @@
{
InteractingGeometry::registerAttributes();
REGISTER_ATTRIBUTE(vertices);
+ #ifdef FACET_TOPO
+ REGISTER_ATTRIBUTE(edgeAdjIds);
+ #endif
}
void InteractingFacet::postProcessAttributes(bool deserializing)
Modified: trunk/pkg/common/DataClass/InteractingGeometry/InteractingFacet.hpp
===================================================================
--- trunk/pkg/common/DataClass/InteractingGeometry/InteractingFacet.hpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/pkg/common/DataClass/InteractingGeometry/InteractingFacet.hpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -9,7 +9,11 @@
#include <yade/core/InteractingGeometry.hpp>
+#include<yade/core/Body.hpp>
+// define this to have topology information about facets enabled;
+// it is necessary for FacetTopologyAnalyzer
+#define FACET_TOPO
class InteractingFacet : public InteractingGeometry {
public:
@@ -34,6 +38,10 @@
Real vl[3];
/// Unit vertice vectors
Vector3r vu[3];
+ #ifdef FACET_TOPO
+ //! facet id's that are adjacent to respective edges
+ vector<body_id_t> edgeAdjIds;
+ #endif
protected:
Modified: trunk/pkg/common/Engine/StandAloneEngine/PersistentSAPCollider.cpp
===================================================================
--- trunk/pkg/common/Engine/StandAloneEngine/PersistentSAPCollider.cpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/pkg/common/Engine/StandAloneEngine/PersistentSAPCollider.cpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -19,6 +19,7 @@
PersistentSAPCollider::PersistentSAPCollider() : Collider()
{
haveDistantTransient=false;
+ ompBodiesMin=0;
nbObjects=0;
xBounds.clear();
@@ -27,7 +28,7 @@
minima.clear();
maxima.clear();
- //timingDeltas=shared_ptr<TimingDeltas>(new TimingDeltas);
+// timingDeltas=shared_ptr<TimingDeltas>(new TimingDeltas);
}
PersistentSAPCollider::~PersistentSAPCollider()
@@ -108,15 +109,22 @@
nbObjects=bodies->size();
// permutation sort of the AABBBounds along the 3 axis performed in a independant manner
- //#pragma omp parallel sections
- {
- //#pragma omp section
- sortBounds(xBounds, nbObjects);
- //#pragma omp section
- sortBounds(yBounds, nbObjects);
- //#pragma omp section
- sortBounds(zBounds, nbObjects);
- }
+ // serial version
+ //if(nbObjects>ompBodiesMin || ompBodiesMin==0){ … }
+ sortBounds(xBounds,nbObjects); sortBounds(yBounds,nbObjects); sortBounds(zBounds,nbObjects);
+ #if 0
+ else {
+ #pragma omp parallel sections
+ {
+ #pragma omp section
+ sortBounds(xBounds, nbObjects);
+ #pragma omp section
+ sortBounds(yBounds, nbObjects);
+ #pragma omp section
+ sortBounds(zBounds, nbObjects);
+ }
+ }
+ #endif
// timingDeltas->checkpoint("sortBounds");
}
@@ -167,26 +175,60 @@
// initialization if the field "value" of the xBounds, yBounds, zBounds arrays
updateBounds(nbElements);
- // modified quick sort of the xBounds, yBounds, zBounds arrays
+ /* Performance note: such was the timing result on initial step of 8k sphere in triaxial test.
+ the findX, findY, findZ take almost the totality of the time.
+ Parallelizing those is vastly beneficial (almost 3x speed increase, which can be quite sensible as the initial
+ findOverlappingBB is really slow http://yade.wikia.com/wiki/Colliders_performace and is done in 3
+ orthogonal directions. Therefore, it is enabled by default.
+
+ Now sortX is right before findX etc, in the same openMP section. Beware that timingDeltas will give garbage
+ results if used in parallelized code.
+
+ ===
+
+ 8k spheres:
+ Name Count Time Rel. time
+ -------------------------------------------------------------------------------------------------------
+ PersistentSAPCollider 1 3568091us 100.00%
+ init 1 21178us 0.59%
+ sortX 1 33225us 0.93%
+ sortY 1 29300us 0.82%
+ sortZ 1 28334us 0.79%
+ findX 1 1708426us 47.88%
+ findY 1 869150us 24.36%
+ findZ 1 867378us 24.31%
+ TOTAL 3556994us 99.69%
+
+ */
+
// The first time these arrays are not sorted so it is faster to use such a sort instead
// of the permutation we are going to use next
- std::sort(xBounds.begin(),xBounds.begin()+2*nbElements,AABBBoundComparator());
- //timingDeltas->checkpoint("sortX");
- std::sort(yBounds.begin(),yBounds.begin()+2*nbElements,AABBBoundComparator());
- //timingDeltas->checkpoint("sortY");
- std::sort(zBounds.begin(),zBounds.begin()+2*nbElements,AABBBoundComparator());
- //timingDeltas->checkpoint("sortZ");
- // initialize the overlappingBB collection
- //for(unsigned int j=0;j<nbElements;j++)
- // overlappingBB[j].clear(); //attention memoire
-
- findOverlappingBB(xBounds, nbElements);
- //timingDeltas->checkpoint("findX");
- findOverlappingBB(yBounds, nbElements);
- //timingDeltas->checkpoint("findY");
- findOverlappingBB(zBounds, nbElements);
- //timingDeltas->checkpoint("findZ");
+ // do not juse timingDeltas with openMP enabled, results will be garbage
+ #pragma omp parallel sections
+ {
+ #pragma omp section
+ {
+ std::sort(xBounds.begin(),xBounds.begin()+2*nbElements,AABBBoundComparator());
+ //timingDeltas->checkpoint("sortX");
+ findOverlappingBB(xBounds, nbElements);
+ //timingDeltas->checkpoint("findX");
+ }
+ #pragma omp section
+ {
+ std::sort(yBounds.begin(),yBounds.begin()+2*nbElements,AABBBoundComparator());
+ //timingDeltas->checkpoint("sortY");
+ findOverlappingBB(yBounds, nbElements);
+ //timingDeltas->checkpoint("findY");
+ }
+ #pragma omp section
+ {
+ std::sort(zBounds.begin(),zBounds.begin()+2*nbElements,AABBBoundComparator());
+ //timingDeltas->checkpoint("sortZ");
+ findOverlappingBB(zBounds, nbElements);
+ //timingDeltas->checkpoint("findZ");
+ }
+ }
}
else updateBounds(nbElements);
}
@@ -240,16 +282,34 @@
void PersistentSAPCollider::updateBounds(int nbElements)
{
- for(int i=0; i < 2*nbElements; i++){
- if (xBounds[i]->lower) xBounds[i]->value = minima[3*xBounds[i]->id+0];
- else xBounds[i]->value = maxima[3*xBounds[i]->id+0];
-
- if (yBounds[i]->lower) yBounds[i]->value = minima[3*yBounds[i]->id+1];
- else yBounds[i]->value = maxima[3*yBounds[i]->id+1];
-
- if (zBounds[i]->lower) zBounds[i]->value = minima[3*zBounds[i]->id+2];
- else zBounds[i]->value = maxima[3*zBounds[i]->id+2];
+ #define _BOUND_UPDATE(bounds,offset) \
+ if (bounds[i]->lower) bounds[i]->value = minima[3*bounds[i]->id+offset]; \
+ else bounds[i]->value = maxima[3*bounds[i]->id+offset];
+ // for small number of bodies, run sequentially
+ #if 0
+ if(nbElements<ompBodiesMin || ompBodiesMin==0){
+ #endif
+ for(int i=0; i < 2*nbElements; i++){
+ _BOUND_UPDATE(xBounds,0);
+ _BOUND_UPDATE(yBounds,1);
+ _BOUND_UPDATE(zBounds,2);
+ }
+ #if 0
}
+ else{
+ // parallelize for large number of bodies (not used, updateBounds takes only about 5% of collider time
+ #pragma omp parallel sections
+ {
+ #pragma omp section
+ for(int i=0; i < 2*nbElements; i++){ _BOUND_UPDATE(xBounds,0); }
+ #pragma omp section
+ for(int i=0; i < 2*nbElements; i++){ _BOUND_UPDATE(yBounds,1); }
+ #pragma omp section
+ for(int i=0; i < 2*nbElements; i++){ _BOUND_UPDATE(zBounds,2); }
+ }
+ }
+ #endif
+ #undef _BOUND_UPDATE
}
Modified: trunk/pkg/common/Engine/StandAloneEngine/PersistentSAPCollider.hpp
===================================================================
--- trunk/pkg/common/Engine/StandAloneEngine/PersistentSAPCollider.hpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/pkg/common/Engine/StandAloneEngine/PersistentSAPCollider.hpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -99,9 +99,13 @@
//! Don't break transient interaction once bodies don't overlap anymore; material law will be responsible for breaking it.
bool haveDistantTransient;
+ //! minimum number of bodies to run updateIds in parallel secions; if 0 (default for now), never run in parallel
+ long ompBodiesMin;
+
void registerAttributes(){
Collider::registerAttributes();
REGISTER_ATTRIBUTE(haveDistantTransient);
+ REGISTER_ATTRIBUTE(ompBodiesMin);
}
DECLARE_LOGGER;
Modified: trunk/pkg/dem/Engine/StandAloneEngine/FacetTopologyAnalyzer.cpp
===================================================================
--- trunk/pkg/dem/Engine/StandAloneEngine/FacetTopologyAnalyzer.cpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/pkg/dem/Engine/StandAloneEngine/FacetTopologyAnalyzer.cpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -2,11 +2,21 @@
#include<yade/pkg-common/InteractingFacet.hpp>
#include<yade/core/MetaBody.hpp>
#include<yade/core/Body.hpp>
+
+CREATE_LOGGER(FacetTopologyAnalyzer);
+YADE_PLUGIN("FacetTopologyAnalyzer");
+
+#ifndef FACET_TOPO
void FacetTopologyAnalyzer::action(MetaBody* rb){
+ throw runtime_error("FACET_TOPO was not enabled in InteractingFacet.hpp at compile-time. Do not use FacetTopologyAnalyzer or recompile.");
+}
+#else
+void FacetTopologyAnalyzer::action(MetaBody* rb){
+ commonEdgesFound=0;
LOG_DEBUG("Projection axis for analysis is "<<projectionAxis);
vector<shared_ptr<VertexData> > vv;
// minimum facet edge length (tolerance scale)
- Real minSqLen=0;
+ Real minSqLen=numeric_limits<Real>::infinity();
FOREACH(const shared_ptr<Body>& b, *rb->bodies){
shared_ptr<InteractingFacet> f=dynamic_pointer_cast<InteractingFacet>(b->interactingGeometry);
if(!f) continue;
@@ -23,20 +33,89 @@
size_t nVertices=vv.size(), j;
for(size_t i=0; i<nVertices; i++){
j=i;
- while(++j<nVertices && (vv[j]->coord-vv[i]->coord)<tolerance){
+ while(++j<nVertices && (vv[j]->coord-vv[i]->coord)<=tolerance){
shared_ptr<VertexData> &vi=vv[i], &vj=vv[j];
- if(abs(vi->pos[0]-vj->pos[0])<tolerance &&
- abs(vi->pos[1]-vj->pos[1])<tolerance &&
- abs(vi->pos[2]-vj->pos[2])<tolerance &&
- (vi->pos-vj->pos).SquaredLength()<tolerance*tolerance){
+ if(abs(vi->pos[0]-vj->pos[0])<=tolerance &&
+ abs(vi->pos[1]-vj->pos[1])<=tolerance &&
+ abs(vi->pos[2]-vj->pos[2])<=tolerance &&
+ (vi->pos-vj->pos).SquaredLength()<=tolerance*tolerance){
// OK, these two vertices touch
- LOG_DEBUG("Vertices "<<vi->id<<"/"<<vi->vertexNo<<" and "<<vj->id<<"/"<<vj->vertexNo<<" close enough.");
+ LOG_TRACE("Vertices "<<vi->id<<"/"<<vi->vertexNo<<" and "<<vj->id<<"/"<<vj->vertexNo<<" close enough.");
// add vertex to the nextIndetical of the one that has lower index; the one that is added will have isLowestIndex=false
if(vi->index<vj->index){ vi->nextIdentical.push_back(vj); vj->isLowestIndex=false; }
else{ vj->nextIdentical.push_back(vi); vi->isLowestIndex=false; }
}
}
}
- /* TODO: create vertex clusters of touching vertices; find what facets they belong to; find whether facets that touch have common edges; compute mutual angle between faces on edge and save that to InteractingFacet */
+ // identity chains start always at lower indices, this way we get all of them
+ sort(vv.begin(),vv.end(),VertexIndexComparator());
+ int maxVertexId=0;
+ FOREACH(shared_ptr<VertexData>& v, vv){
+ if(v->vertexId<0){
+ assert(v->isLowestIndex);
+ v->vertexId=maxVertexId++;
+ }
+ FOREACH(shared_ptr<VertexData>& vNext, v->nextIdentical){
+ vNext->vertexId=v->vertexId;
+ }
+ if(v->vertexId>=0) continue; // already assigned
+ }
+ LOG_DEBUG("Found "<<maxVertexId<<" unique vertices.");
+ // add FacetTopology for all facets; index within the topo array is the body id
+ vector<shared_ptr<FacetTopology> > topo(rb->bodies->size()); // initialized with the default ctor
+ FOREACH(shared_ptr<VertexData>& v, vv){
+ if(!topo[v->id]) topo[v->id]=shared_ptr<FacetTopology>(new FacetTopology(v->id));
+ topo[v->id]->vertices[v->vertexNo]=v->vertexId;
+ }
+ // make sure all facets have their vertex id's assigned
+ // add non-empty ones to topo1 that will be used for adjacency search afterwards
+ vector<shared_ptr<FacetTopology> > topo1;
+ for(size_t i=0; i<topo.size(); i++){
+ shared_ptr<FacetTopology> t=topo[i];
+ if(!t) continue;
+ if(t->vertices[0]<0 || t->vertices[1]<0 || t->vertices[2]<0){
+ LOG_FATAL("Facet #"<<i<<": some vertex has no integrized vertexId assigned!!");
+ LOG_FATAL("Vertices are: "<<t->vertices[0]<<","<<t->vertices[1]<<","<<t->vertices[2]);
+ throw logic_error("Facet vertex has no integrized vertex assigned?!");
+ }
+ topo1.push_back(t);
+ }
+ sort(topo1.begin(),topo1.end(),TopologyIndexComparator());
+ size_t nTopo=topo1.size();
+ for(size_t i=0; i<nTopo; i++){
+ size_t j=i;
+ while(++j<nTopo){
+ const shared_ptr<FacetTopology>& ti(topo1[i]), &tj(topo1[j]);
+ LOG_TRACE("Analyzing possibly-adjacent facets #"<<ti->id<<" #"<<tj->id<<" (vertices "<<ti->vertices[0]<<","<<ti->vertices[1]<<","<<ti->vertices[2]<<"; "<<tj->vertices[0]<<","<<ti->vertices[1]<<","<<ti->vertices[2]<<")");
+ vector<size_t> vvv; // array of common vertices
+ for(size_t k=0; k<3; k++){
+ if (ti->vertices[k]==tj->vertices[0]) vvv.push_back(ti->vertices[k]);
+ else if(ti->vertices[k]==tj->vertices[1]) vvv.push_back(ti->vertices[k]);
+ else if(ti->vertices[k]==tj->vertices[2]) vvv.push_back(ti->vertices[k]);
+ }
+ if(vvv.size()==0) break; // reached end of those that have the lowest-id vertex in common
+ if(vvv.size()==1) continue; // only one edge in common
+ assert(vvv.size()!=3); // same coords? nonsense
+ assert(vvv.size()==2);
+ vector<int> edge(2,0);
+ // identify what edge are we at, for both facets
+ for(int k=0; k<2; k++){
+ for(edge[k]=0; edge[k]<3; edge[k]++){
+ const shared_ptr<FacetTopology>& tt( k==0 ? ti : tj);
+ size_t v1=tt->vertices[edge[k]],v2=tt->vertices[(edge[k]+1)%3];
+ if((vvv[0]==v1 && vvv[1]==v2) || (vvv[0]==v2 && vvv[1]==v1)) break;
+ if(edge[k]==2){
+ LOG_FATAL("No edge identified for 2 vertices "<<vvv[0]<<","<<vvv[1]<<" (facet #"<<tt->id<<" is: "<<tt->vertices[0]<<","<<tt->vertices[1]<<","<<tt->vertices[2]<<")");
+ throw logic_error("No edge identified for given vertices.");
+ }
+ }
+ }
+ // add adjacency information to the facet itself
+ YADE_PTR_CAST<InteractingFacet>((*rb->bodies)[ti->id]->interactingGeometry)->edgeAdjIds[edge[0]]=tj->id;
+ YADE_PTR_CAST<InteractingFacet>((*rb->bodies)[tj->id]->interactingGeometry)->edgeAdjIds[edge[1]]=tj->id;
+ commonEdgesFound++;
+ LOG_TRACE("Added adjacency information for #"<<ti->id<<"+#"<<tj->id<<" (common edges "<<edge[0]<<"+"<<edge[1]<<")");
+ }
+ }
}
-
+#endif
Modified: trunk/pkg/dem/Engine/StandAloneEngine/FacetTopologyAnalyzer.hpp
===================================================================
--- trunk/pkg/dem/Engine/StandAloneEngine/FacetTopologyAnalyzer.hpp 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/pkg/dem/Engine/StandAloneEngine/FacetTopologyAnalyzer.hpp 2009-04-08 20:27:04 UTC (rev 1750)
@@ -9,7 +9,7 @@
*/
class FacetTopologyAnalyzer: public StandAloneEngine{
struct VertexData{
- VertexData(body_id_t _id, int _vertexNo, Vector3r _pos, Real _coord): id(_id), vertexNo(_vertexNo), coord(_coord), pos(_pos){index=3*id+vertexNo; isLowestIndex=true;}
+ VertexData(body_id_t _id, int _vertexNo, Vector3r _pos, Real _coord): id(_id), vertexNo(_vertexNo), coord(_coord), pos(_pos){index=3*id+vertexNo; isLowestIndex=true; vertexId=-1;}
//! Facet (body id) that we represent
body_id_t id;
//! vertex number within this Facet
@@ -24,21 +24,37 @@
bool isLowestIndex;
//! vertices that are "identical" with this one, but have higer indices
vector<shared_ptr<VertexData> > nextIdentical;
+ //! id of vertex, once they have id's assigned
+ long vertexId;
};
struct VertexComparator{
bool operator()(const shared_ptr<VertexData>& v1, const shared_ptr<VertexData>& v2){return v1->coord<v2->coord;}
};
-
+ struct VertexIndexComparator{
+ bool operator()(const shared_ptr<VertexData>& v1, const shared_ptr<VertexData>& v2){return v1->index<v2->index;}
+ };
+ struct FacetTopology{
+ FacetTopology(body_id_t _id): id(_id){vertices[0]=vertices[1]=vertices[2]=-1;}
+ //! integrized vertices
+ long vertices[3];
+ //! facet id, for back reference
+ body_id_t id;
+ };
+ struct TopologyIndexComparator{
+ bool operator()(const shared_ptr<FacetTopology>& t1, const shared_ptr<FacetTopology>& t2){ return min(t1->vertices[0],min(t1->vertices[1],t1->vertices[2]))<min(t2->vertices[0],min(t2->vertices[1],t2->vertices[2])); }
+ };
public:
//! Axis along which to do the initial vertex sort
Vector3r projectionAxis;
- //! maximum distance of "identical" vertices, relative to maximum facet size
+ //! maximum distance of "identical" vertices, relative to minimum facet size
Real relTolerance;
+ //! how many common edges were identified during last run
+ long commonEdgesFound;
void action(MetaBody*);
- FacetTopologyAnalyzer(): projectionAxis(Vector3r::UNIT_X), relTolerance(1e-4) {}
+ FacetTopologyAnalyzer(): projectionAxis(Vector3r::UNIT_X), relTolerance(1e-4), commonEdgesFound(0) {}
DECLARE_LOGGER;
REGISTER_CLASS_AND_BASE(FacetTopologyAnalyzer,StandAloneEngine);
- REGISTER_ATTRIBUTES(StandAloneEngine, /* none */);
+ REGISTER_ATTRIBUTES(StandAloneEngine, (projectionAxis)(relTolerance));
};
REGISTER_SERIALIZABLE(FacetTopologyAnalyzer);
Added: trunk/scripts/test/facet-topo.py
===================================================================
--- trunk/scripts/test/facet-topo.py 2009-04-06 21:40:30 UTC (rev 1749)
+++ trunk/scripts/test/facet-topo.py 2009-04-08 20:27:04 UTC (rev 1750)
@@ -0,0 +1,24 @@
+import yade.log
+yade.log.setLevel('FacetTopologyAnalyzer',yade.log.TRACE)
+
+# Note: FacetTopologyAnalyzer is normally run as an initializer;
+# it is only for testing sake that it is in O.engines here.
+O.engines=[FacetTopologyAnalyzer(projectionAxis=(0,0,1),label='topo'),]
+
+# most simple case: no touch at all
+if 1:
+ O.bodies.append([
+ utils.facet([(0,0,0),(1,0,0),(0,1,0)]),
+ utils.facet([(0,0,1),(1,0,1),(0,1,1)]),
+ ])
+ O.step();
+ assert(topo['commonEdgesFound']==0)
+if 1:
+ O.bodies.clear()
+ O.bodies.append([
+ utils.facet([(0,0,0),(1,0,0),(0,1,0)]),
+ 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(topo['commonEdgesFound']==1)