← Back to team overview

yade-dev team mailing list archive

[svn] r1538 - in trunk: core extra extra/clump gui/py pkg/common/Engine/MetaEngine pkg/dem/Engine/StandAloneEngine scripts

 

Author: eudoxos
Date: 2008-10-07 09:02:48 +0200 (Tue, 07 Oct 2008)
New Revision: 1538

Added:
   trunk/scripts/chain-distant-interactions.py
Modified:
   trunk/core/Interaction.cpp
   trunk/extra/Brefcom.cpp
   trunk/extra/clump/Shop.cpp
   trunk/extra/clump/Shop.hpp
   trunk/gui/py/_utils.cpp
   trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.cpp
   trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.hpp
   trunk/pkg/common/Engine/MetaEngine/InteractionPhysicsMetaEngine.cpp
   trunk/pkg/common/Engine/MetaEngine/InteractionPhysicsMetaEngine.hpp
   trunk/pkg/dem/Engine/StandAloneEngine/ElasticContactLaw.cpp
   trunk/pkg/dem/Engine/StandAloneEngine/ElasticContactLaw.hpp
Log:
1. Add InteractionGeometryMetaEngine::explicitAction and InteractionPhysicsMetaEngine::explicitAction for creating contacts manually using the dispatcher
2. add utils.createInteraction(id1,id2) that requests explicit transient interaction creation
3. Add sample ElasticContactLaw2 (in ElasticContactLaw.cpp) that uses new SpheresContactGeometry code and can be used for "persistent" (transient but not deleted by the collider) contacts.
4. Add Shop::applyForceAtContactPoint (applies contact force at contact point to both bodies (reversed for body2) and moments acting on their cenroids as well)
5. All the previous new functionality is demonstrated in scripts/chain-distant-interactions.py.



Modified: trunk/core/Interaction.cpp
===================================================================
--- trunk/core/Interaction.cpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/core/Interaction.cpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -27,7 +27,6 @@
 {	
 	isNew = true;
 	isReal = false;
-	isNeighbor = true;
 	isNeighbor = true;//NOTE : TriangulationCollider needs that
 
 }

Modified: trunk/extra/Brefcom.cpp
===================================================================
--- trunk/extra/Brefcom.cpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/extra/Brefcom.cpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -128,7 +128,7 @@
 	Shop::Bex::force(id1,rootBody)+=force;
 	Shop::Bex::force(id2,rootBody)-=force;
 	Shop::Bex::momentum(id1,rootBody)+=(contGeom->contactPoint-contGeom->pos1).Cross(force);
-	Shop::Bex::momentum(id1,rootBody)-=(contGeom->contactPoint-contGeom->pos2).Cross(force);
+	Shop::Bex::momentum(id2,rootBody)-=(contGeom->contactPoint-contGeom->pos2).Cross(force);
 }
 
 void BrefcomLaw::action(MetaBody* _rootBody){

Modified: trunk/extra/clump/Shop.cpp
===================================================================
--- trunk/extra/clump/Shop.cpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/extra/clump/Shop.cpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -97,13 +97,22 @@
 	}
 }
 
-#define __BEX_ACCESS(retType,shopBexMember,bexClass,bexIdx,bexAttribute) retType& Shop::Bex::shopBexMember(body_id_t id,MetaBody* mb){ assert(bexIdx>=0); return static_pointer_cast<bexClass>((mb?mb:Omega::instance().getRootBody().get())->physicalActions->find(id,bexIdx))->bexAttribute; }
+#define __BEX_ACCESS(retType,shopBexMember,bexClass,bexIdx,bexAttribute) retType& Shop::Bex::shopBexMember(body_id_t id,MetaBody* mb){ assert(bexIdx>=0); shared_ptr<PhysicalActionContainer> pac=(mb?mb:Omega::instance().getRootBody().get())->physicalActions; /*if((long)pac->size()<=id) throw invalid_argument("No " #shopBexMember " for #"+lexical_cast<string>(id)+" (max="+lexical_cast<string>(((long)pac->size()-1))+")");*/ return static_pointer_cast<bexClass>(pac->find(id,bexIdx))->bexAttribute; }
 __BEX_ACCESS(Vector3r,force,Force,forceIdx,force);
 __BEX_ACCESS(Vector3r,momentum,Momentum,momentumIdx,momentum);
 __BEX_ACCESS(Vector3r,globalStiffness,GlobalStiffness,globalStiffnessIdx,stiffness);
 __BEX_ACCESS(Vector3r,globalRStiffness,GlobalStiffness,globalStiffnessIdx,Rstiffness);
 #undef __BEX_ACCESS
 
+/* Apply force on contact point to 2 bodies; the force is oriented as it applies on the first body and is reversed on the second.
+ *
+ * Shop::Bex::initCache must have been called at some point. */
+void Shop::applyForceAtContactPoint(const Vector3r& force, const Vector3r& contPt, body_id_t id1, const Vector3r& pos1, body_id_t id2, const Vector3r& pos2, MetaBody* rootBody){
+	Shop::Bex::force(id1,rootBody)+=force;
+	Shop::Bex::force(id2,rootBody)-=force;
+	Shop::Bex::momentum(id1,rootBody)+=(contPt-pos1).Cross(force);
+	Shop::Bex::momentum(id2,rootBody)-=(contPt-pos2).Cross(force);
+}
 
 
 Real Shop::unbalancedForce(bool useMaxForce, MetaBody* _rb){
@@ -496,6 +505,26 @@
 	return dt;
 }
 
+
+shared_ptr<Interaction> Shop::createExplicitInteraction(body_id_t id1, body_id_t id2){
+	InteractionGeometryMetaEngine* geomMeta=NULL;
+	InteractionPhysicsMetaEngine* physMeta=NULL;
+	shared_ptr<MetaBody> rb=Omega::instance().getRootBody();
+	if(rb->transientInteractions->find(body_id_t(id1),body_id_t(id2))!=0) throw runtime_error(string("transientInteraction already exists between #")+lexical_cast<string>(id1)+" and "+lexical_cast<string>(id2));
+	FOREACH(const shared_ptr<Engine>& e, rb->engines){
+		if(!geomMeta) { geomMeta=dynamic_cast<InteractionGeometryMetaEngine*>(e.get()); if(geomMeta) continue; }
+		if(!physMeta) { physMeta=dynamic_cast<InteractionPhysicsMetaEngine*>(e.get()); if(physMeta) continue; }
+		if(geomMeta&&physMeta){break;}
+	}
+	if(!geomMeta) throw runtime_error("No InteractionGeometryMetaEngine in engines.");
+	if(!physMeta) throw runtime_error("No InteractionPhysicsMetaEngine in engines.");
+	shared_ptr<Body> b1=Body::byId(id1,rb), b2=Body::byId(id2,rb);
+	shared_ptr<Interaction> i=geomMeta->explicitAction(b1,b2);
+	physMeta->explicitAction(b1->physicalParameters,b2->physicalParameters,i);
+	rb->transientInteractions->insert(i);
+	return i;
+}
+
 Shop::sphereGeomStruct Shop::smallSdecXyzData[]={
 	{0.027814,0.028311,0.053055,0.006921},
 	{0.040115,0.039488,0.051634,0.009072},

Modified: trunk/extra/clump/Shop.hpp
===================================================================
--- trunk/extra/clump/Shop.hpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/extra/clump/Shop.hpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -102,4 +102,10 @@
 
 		//! Get unbalanced force of the whole simulation
 		static Real unbalancedForce(bool useMaxForce=false, MetaBody* _rb=NULL);
+
+		//! create transientInteraction between 2 bodies, using existing MetaEngine in Omega
+		static shared_ptr<Interaction> createExplicitInteraction(body_id_t id1, body_id_t id2);
+
+		//! apply force on contact point on both bodies (reversed on body 2)
+		static void applyForceAtContactPoint(const Vector3r& force, const Vector3r& contPt, body_id_t id1, const Vector3r& pos1, body_id_t id2, const Vector3r& pos2, MetaBody* rb);
 };

Modified: trunk/gui/py/_utils.cpp
===================================================================
--- trunk/gui/py/_utils.cpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/gui/py/_utils.cpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -4,7 +4,7 @@
 #include<yade/core/Omega.hpp>
 #include<yade/pkg-common/Sphere.hpp>
 #include<yade/pkg-dem/SpheresContactGeometry.hpp>
-#include<yade/extra/Brefcom.hpp>
+#include<yade/pkg-common/NormalShearInteractions.hpp>
 #include<cmath>
 using namespace boost::python;
 
@@ -73,8 +73,8 @@
 	Real E=0;
 	FOREACH(const shared_ptr<Interaction>&i, *rb->transientInteractions){
 		if(!i->interactionPhysics) continue;
-		shared_ptr<BrefcomContact> bc=dynamic_pointer_cast<BrefcomContact>(i->interactionPhysics); if(!bc) continue;
-		shared_ptr<SpheresContactGeometry> geom=dynamic_pointer_cast<SpheresContactGeometry>(i->interactionGeometry); if(!bc){LOG_ERROR("Brefcom contact doesn't have SpheresContactGeomety associated?!"); continue;}
+		shared_ptr<NormalShearInteraction> bc=dynamic_pointer_cast<NormalShearInteraction>(i->interactionPhysics); if(!bc) continue;
+		shared_ptr<SpheresContactGeometry> geom=dynamic_pointer_cast<SpheresContactGeometry>(i->interactionGeometry); if(!bc){LOG_ERROR("NormalShearInteraction contact doesn't have SpheresContactGeomety associated?!"); continue;}
 		const shared_ptr<Body>& b1=Body::byId(i->getId1(),rb), b2=Body::byId(i->getId2(),rb);
 		bool isIn1=isInBB(b1->physicalParameters->se3.position,bbMin,bbMax), isIn2=isInBB(b2->physicalParameters->se3.position,bbMin,bbMax);
 		if(!isIn1 && !isIn2) continue;
@@ -89,9 +89,7 @@
 			//cerr<<"Interaction crosses AABB boundary, weight is "<<weight<<endl;
 			//LOG_DEBUG("Interaction crosses AABB boundary, weight is "<<weight);
 		} else {assert(isIn1 && isIn2); /* cerr<<"Interaction inside, weight is "<<weight<<endl;*/ /*LOG_DEBUG("Interaction inside, weight is "<<weight);*/}
-		E+=geom->d0*weight*(.5*bc->E*bc->crossSection*pow(geom->epsN(),2)+.5*bc->G*bc->crossSection*pow(geom->epsT().Length(),2));
-		//TRVAR5(bc->crossSection,bc->E,bc->G,bc->epsN,bc->epsT.Length());;
-		//cerr<<bc->crossSection<<","<<bc->E<<","<<bc->G<<","<<bc->epsN<<","<<bc->epsT.Length()<<endl;
+		E+=geom->d0*weight*(.5*bc->kn*pow(geom->epsN(),2)+.5*bc->ks*pow(geom->epsT().Length(),2));
 	}
 	return E;
 }
@@ -158,7 +156,52 @@
 {
 	return vec2tuple(Shop::inscribedCircleCenter(Vector3r(python::extract<double>(v0[0]),python::extract<double>(v0[1]),python::extract<double>(v0[2])), Vector3r(python::extract<double>(v1[0]),python::extract<double>(v1[1]),python::extract<double>(v1[2])), Vector3r(python::extract<double>(v2[0]),python::extract<double>(v2[1]),python::extract<double>(v2[2]))));
 }
+/* Sum moments acting on bodies within mask.
+ *
+ * @param mask is Body::groupMask that must match for a body to be taken in account.
+ * @param axis is the direction of axis with respect to which the moment is calculated.
+ * @param axisPt is a point on the axis.
+ *
+ * The computation is trivial: moment from force is is by definition r×F, where r
+ * is position relative to axisPt; moment from moment is m; such moment per body is
+ * projected onto axis.
+ */
+Real sumBexMoments(int mask, python::tuple _axis, python::tuple _axisPt){
+	Shop::Bex::initCache();
+	shared_ptr<MetaBody> rb=Omega::instance().getRootBody();
+	Real ret;
+	Vector3r axis=tuple2vec(_axis), axisPt=tuple2vec(_axisPt);
+	FOREACH(const shared_ptr<Body> b, *rb->bodies){
+		if(!b->maskOk(mask)) continue;
+		const Vector3r& m=Shop::Bex::momentum(b->getId(),rb.get());
+		const Vector3r& f=Shop::Bex::force(b->getId(),rb.get());
+		Vector3r r=b->physicalParameters->se3.position-axisPt;
+		ret+=axis.Dot(m+r.Cross(f));
+	}
+	return ret;
+}
+/* Sum forces actiong on bodies within mask.
+ *
+ * @param mask groupMask of matching bodies
+ * @param direction direction in which forces are summed
+ *
+ */
+Real sumBexForces(int mask, python::tuple _direction){
+	Shop::Bex::initCache();
+	shared_ptr<MetaBody> rb=Omega::instance().getRootBody();
+	Real ret;
+	Vector3r direction=tuple2vec(_direction);
+	FOREACH(const shared_ptr<Body> b, *rb->bodies){
+		if(!b->maskOk(mask)) continue;
+		const Vector3r& f=Shop::Bex::force(b->getId(),rb.get());
+		ret+=direction.Dot(f);
+	}
+	return ret;
+}
 
+// for now, don't return anything, since we would have to include the whole yadeControl.cpp because of pyInteraction
+void Shop__createExplicitInteraction(body_id_t id1, body_id_t id2){ (void) Shop::createExplicitInteraction(id1,id2);}
+
 BOOST_PYTHON_FUNCTION_OVERLOADS(unbalancedForce_overloads,Shop::unbalancedForce,0,1);
 
 BOOST_PYTHON_MODULE(_utils){
@@ -172,6 +215,9 @@
 	def("elasticEnergy",elasticEnergyInAABB);
 	def("inscribedCircleCenter",inscribedCircleCenter);
 	def("unbalancedForce",&Shop::unbalancedForce,unbalancedForce_overloads(args("useMaxForce")));
+	def("sumBexForces",sumBexForces);
+	def("sumBexMoments",sumBexMoments);
+	def("createInteraction",Shop__createExplicitInteraction);
 }
 
 

Modified: trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.cpp
===================================================================
--- trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.cpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.cpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -12,7 +12,22 @@
 
 
 #include<yade/core/MetaBody.hpp>
+	
+/* Single dispatch for given pair of bodies, returning new interaction.
+ *
+ * The caller is responsible for inserting the interaction into some interaction container.
+ *
+ * The EngineUnit must not fail (return false).
+ */
 
+shared_ptr<Interaction> InteractionGeometryMetaEngine::explicitAction(const shared_ptr<Body>& b1, const shared_ptr<Body> b2){
+	assert(b1->interactingGeometry && b2->interactingGeometry);
+	shared_ptr<Interaction> i(new Interaction(b1->getId(),b2->getId()));
+	i->isReal=true;
+	bool op=operator()(b1->interactingGeometry,b2->interactingGeometry,b1->physicalParameters->se3,b2->physicalParameters->se3,i);
+	if(!op) throw runtime_error("InteractionGeometryMetaEngine::explicitAction could not dispatch for given types ("+b1->interactingGeometry->getClassName()+","+b2->interactingGeometry->getClassName()+") or the dispatchee returned false.");
+	return i;
+}
 
 void InteractionGeometryMetaEngine::action(MetaBody* ncb)
 {

Modified: trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.hpp
===================================================================
--- trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.hpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/pkg/common/Engine/MetaEngine/InteractionGeometryMetaEngine.hpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -37,6 +37,7 @@
 {
 	public :
 		virtual void action(MetaBody*);
+		shared_ptr<Interaction> explicitAction(const shared_ptr<Body>& b1, const shared_ptr<Body> b2);
 
 	REGISTER_CLASS_NAME(InteractionGeometryMetaEngine);
 	REGISTER_BASE_CLASS_NAME(MetaEngine2D);

Modified: trunk/pkg/common/Engine/MetaEngine/InteractionPhysicsMetaEngine.cpp
===================================================================
--- trunk/pkg/common/Engine/MetaEngine/InteractionPhysicsMetaEngine.cpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/pkg/common/Engine/MetaEngine/InteractionPhysicsMetaEngine.cpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -10,6 +10,15 @@
 
 
 #include<yade/core/MetaBody.hpp>
+/* Single dispatch for given bodies pp's and interaction.
+ * 
+ * The interaction must be real (needed?).
+ */
+void InteractionPhysicsMetaEngine::explicitAction(shared_ptr<PhysicalParameters>& pp1, shared_ptr<PhysicalParameters>& pp2, shared_ptr<Interaction>& i){
+	// should we throw instead of asserting?
+	assert(i->isReal);
+	operator()(pp1,pp2,i);
+}
 
 
 void InteractionPhysicsMetaEngine::action(MetaBody* ncb)

Modified: trunk/pkg/common/Engine/MetaEngine/InteractionPhysicsMetaEngine.hpp
===================================================================
--- trunk/pkg/common/Engine/MetaEngine/InteractionPhysicsMetaEngine.hpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/pkg/common/Engine/MetaEngine/InteractionPhysicsMetaEngine.hpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -30,6 +30,7 @@
 {		
 	public :
 		virtual void action(MetaBody*);
+		void explicitAction(shared_ptr<PhysicalParameters>& pp1, shared_ptr<PhysicalParameters>& pp2, shared_ptr<Interaction>& i);
 
 	REGISTER_CLASS_NAME(InteractionPhysicsMetaEngine);
 	REGISTER_BASE_CLASS_NAME(MetaEngine2D);

Modified: trunk/pkg/dem/Engine/StandAloneEngine/ElasticContactLaw.cpp
===================================================================
--- trunk/pkg/dem/Engine/StandAloneEngine/ElasticContactLaw.cpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/pkg/dem/Engine/StandAloneEngine/ElasticContactLaw.cpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -17,7 +17,34 @@
 #include<yade/pkg-common/Momentum.hpp>
 #include<yade/core/PhysicalAction.hpp>
 
+#include<yade/extra/Shop.hpp>
 
+ElasticContactLaw2::ElasticContactLaw2(){
+	Shop::Bex::initCache();
+	isCohesive=true;
+}
+
+ElasticContactLaw2::~ElasticContactLaw2(){}
+
+void ElasticContactLaw2::action(MetaBody* rb){
+	FOREACH(shared_ptr<Interaction> i, *rb->transientInteractions){
+		if(!i->isReal) continue;
+		shared_ptr<SpheresContactGeometry> contGeom=YADE_PTR_CAST<SpheresContactGeometry>(i->interactionGeometry);
+		shared_ptr<ElasticContactInteraction> contPhys=YADE_PTR_CAST<ElasticContactInteraction>(i->interactionPhysics);
+		assert(contGeom); assert(contPhys);
+		if(!contGeom->hasShear) throw runtime_error("SpheresContactGeometry::hasShear must be true for ElasticContactLaw2");
+		Real Fn=contPhys->kn*contGeom->displacementN(); // scalar normal force; displacementN()>=0 ≡ elongation of the contact
+		if(!isCohesive && contGeom->displacementN()>0){ cerr<<"deleting"<<endl; /* delete the interaction */ i->isReal=false; continue;}
+		contPhys->normalForce=Fn*contGeom->normal;
+		contGeom->slipToDisplacementTMax(max(0.,(-Fn*contPhys->tangensOfFrictionAngle)/contPhys->ks)); // limit shear displacement -- Coulomb criterion
+		contPhys->shearForce=contPhys->ks*contGeom->displacementT();
+		Vector3r force=contPhys->shearForce+contPhys->normalForce;
+		Shop::applyForceAtContactPoint(force,contGeom->contactPoint,i->getId1(),contGeom->pos1,i->getId2(),contGeom->pos2,rb);
+	}
+}
+
+
+
 ElasticContactLaw::ElasticContactLaw() : InteractionSolver() , actionForce(new Force) , actionMomentum(new Momentum)
 {
 	sdecGroupMask=1;

Modified: trunk/pkg/dem/Engine/StandAloneEngine/ElasticContactLaw.hpp
===================================================================
--- trunk/pkg/dem/Engine/StandAloneEngine/ElasticContactLaw.hpp	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/pkg/dem/Engine/StandAloneEngine/ElasticContactLaw.hpp	2008-10-07 07:02:48 UTC (rev 1538)
@@ -17,6 +17,23 @@
 
 class PhysicalAction;
 
+class ElasticContactLaw2: public InteractionSolver{
+	public:
+	//! this should really be property of the interaction, but for simplicity keep it here now...
+	bool isCohesive;
+	ElasticContactLaw2();
+	virtual ~ElasticContactLaw2();
+	void action(MetaBody*);
+	void registerAttributes(){
+		InteractionSolver::registerAttributes();
+		REGISTER_ATTRIBUTE(isCohesive);
+	}
+	NEEDS_BEX("Force","Momentum");
+	REGISTER_CLASS_NAME(ElasticContactLaw2);
+	REGISTER_BASE_CLASS_NAME(InteractionSolver);
+};
+REGISTER_SERIALIZABLE(ElasticContactLaw2,false);
+
 class ElasticContactLaw : public InteractionSolver
 {
 /// Attributes

Added: trunk/scripts/chain-distant-interactions.py
===================================================================
--- trunk/scripts/chain-distant-interactions.py	2008-10-07 06:19:24 UTC (rev 1537)
+++ trunk/scripts/chain-distant-interactions.py	2008-10-07 07:02:48 UTC (rev 1538)
@@ -0,0 +1,28 @@
+#!/usr/local/bin/yade-trunk -x
+# -*- encoding=utf-8 -*-
+
+o=Omega()
+o.initializers=[
+	StandAloneEngine('PhysicalActionContainerInitializer'),
+	MetaEngine('BoundingVolumeMetaEngine',[EngineUnit('InteractingSphere2AABB'),EngineUnit('InteractingBox2AABB'),EngineUnit('MetaInteractingGeometry2AABB')])
+	]
+o.engines=[
+	StandAloneEngine('PhysicalActionContainerReseter'),
+	MetaEngine('BoundingVolumeMetaEngine',[EngineUnit('InteractingSphere2AABB'),EngineUnit('MetaInteractingGeometry2AABB')
+	]),
+	StandAloneEngine('PersistentSAPCollider',{'haveDistantTransient':True}),
+	MetaEngine('InteractionGeometryMetaEngine',[EngineUnit('InteractingSphere2InteractingSphere4SpheresContactGeometry',{'hasShear':True}),]),
+	MetaEngine('InteractionPhysicsMetaEngine',[EngineUnit('SimpleElasticRelationships')]),
+	StandAloneEngine('ElasticContactLaw2',{'isCohesive':True}),
+	DeusExMachina('GravityEngine',{'gravity':[0,0,-1e5]}),
+	DeusExMachina('NewtonsDampedLaw',{'damping':0.2})
+]
+from yade import utils
+for n in range(20):
+	o.bodies.append(utils.sphere([0,n,0],.5,dynamic=(n>0),color=[1-(n/20.),n/20.,0],young=30e9,poisson=.3,density=2400))
+	# looks for metaengine found in Omega() and uses those
+	if n>0: utils.createInteraction(n-1,n)
+
+
+o.dt=.04*utils.PWaveTimeStep()
+o.save('/tmp/a.xml.bz2')


Property changes on: trunk/scripts/chain-distant-interactions.py
___________________________________________________________________
Name: svn:executable
   + *