Loop - array -->Find out the strength needed to move each particle

Asked by rayolau

Hi guys! First I expose I try to do, and then my problem. Thanks in advance!!

I have a script that save the Id. of particles and others values of these particles like this:

array1 = [ id [0], [1], [2], [3], [4]] [C] = columns ; [R] = rows
This part of script works ok.

The problem comes now. For each particle of this array, I want apply a force which will increase until the displacement of the particle with respect to the x axis occurs. The objective is find out the force necessary for move each particle. I want to loop through the array by rows, so that when the particle in the first row meets the condition of displacement to the next particle in the next row, and up through the array completely and obtain for each of the particles the force required to move them. I have written this, but fails to apply force and also, I'm not sure that in this way through each of the rows, but it does for columns.

The part of script fails is this:

        array2=[]
 Xforce=0

 for xx in range(0,len(array1)):
  id_clump=O.bodies[array1[xx][0]] # [0] --> column Id array1
  Xforce=Xforce+0.001
  Yforce=0
  Zforce=0
  O.forces.addF(id_clump,(Xforce,Yforce,Zforce))

  if id_clump.state.displ()[0]>0: #[0] --> X axis

   value=Xforce/array[xx][2] #[2] --> column 2 of array 1
                        array2.append([array1[xx][0],value)

   np.savetxt('forces_id.out',array2,delimiter=',')

 Xforce=0 #to set the counter to zero force, before moving to the next particle.

The error:
Python argument types in
    ForceContainer.addF(ForceContainer, Body, tuple)
did not match C++ signature:
    addF(pyForceContainer {lvalue}, long id, Eigen::Matrix<double, 3, 1, 0, 3, 1> f, bool permanent=False)

Thanks for any ideas or suggestions!

Question information

Language:
English Edit question
Status:
Answered
For:
Yade Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:
Revision history for this message
Jan Stránský (honzik) said :
#1

Hello,

first of all, I did not get at all what you are trying to achieve :-)

anyway:

>
> for xx in range(0,len(array1)):
> id_clump=O.bodies[array1[xx][0]] # [0] --> column
> Id array1
>

as the error message says, id_clump is now instance of Body (not its id!),
that's why its usage in addForce function fails. Try

id_clump=O.bodies[array1[xx][0]].id

HTH
Jan

Revision history for this message
rayolau (rayolau88) said :
#2

Thanks for your repply! =)

I'll try to summarize the case I am analyzing. I created a granular bed, in which the particles are clumps.
The first step is to store in an array (array 1), identities, diameter, weight ... of the CLUMPS that accomplish conditions established previously.

My object is determine the value of force necessary to move each one of this particles (particles stored in array 1), ie, determine the necessary applied force (in x axis) over each particle to overcome the friction caused by the contact of each of those particles (id clumps array1) with other particles of the granular bed.

I tried your suggestion and now I have a new error:

---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/usr/bin/yadedaily in <module>()

/usr/bin/yadedaily in identificacion()
    226 Xforce=0
    227 O.forces.addF(id_piedra,(fuerzax,fuerzay,fuerzaz))
--> 228 if id_clump.state.displ()[0]>0:
    229 value=Xforce/array1[xx][2]
    230 value2=2*value*array1[xx][3]*array1[xx][3]

AttributeError: 'int' object has no attribute 'state'
---------------------------------------------------------------------------

anyway, I'm not sure this matrix by crossing the rows, so that, until the first particle meets the condition of displacement, go to next row, ie, the next particle of which is to determine the force required to move it.

Thanks,
Laura

Revision history for this message
Jan Stránský (honzik) said :
#3

Hi Laura,

>
> I tried your suggestion and now I have a new error:
>
> ---------------------------------------------------------------------------
> AttributeError Traceback (most recent call last)
> /usr/bin/yadedaily in <module>()
>
> /usr/bin/yadedaily in identificacion()
> 226 Xforce=0
> 227 O.forces.addF(id_piedra,(fuerzax,fuerzay,fuerzaz))
> --> 228 if id_clump.state.displ()[0]>0:
> 229 value=Xforce/array1[xx][2]
> 230 value2=2*value*array1[xx][3]*array1[xx][3]
>
> AttributeError: 'int' object has no attribute 'state'
> ---------------------------------------------------------------------------
>
>
The problem is, as the error message says, that you have id_clump, id of a
body, i.e. int value, and you want to access its state, which can't work.
You need actual body (not id) to access its state.

I would suggest to return to your original version, but rename id_clump
(since it is not ID and thus is confusing) to e.g. clump. On the next line
you can define
id_clump=clump.id

So you have both body instance and its id and use them in correct
positions, e.g. accessing state.displ() on clump (clump.state.displ()) and
using id in addForce (O.forces.addF(id_clump,force))

I will try to read your explanation later when I have time :-)

cheers
Jan

Revision history for this message
rayolau (rayolau88) said :
#4

I tried what you said, and I still got to keep an array containing the needed to move each of the particles applied force. Thanks for the interest, I'll keep trying. If you need to explain better what I'm doing to help, ask what you need!

Thank you for the answers =)
Laura

---------------------------------------------------------------------------
NameError Traceback (most recent call last)
/usr/bin/yadedaily in <module>()

/usr/bin/yadedaily in identificacion()
    221 xforce=0
    222 for xx in range(0,len(array1)):
--> 223 id_clump=clump.id
    224 clump.id=O.bodies[array1[xx][0]]
    225 xforce=xforce+0.001

NameError: global name 'clump' is not defined

Revision history for this message
rayolau (rayolau88) said :
#5

Hi Jan, thanks for the above replies. I managed to apply the force on the corresponding Clump Id.

The code I've written does not give any error, but I can not determine the force needed to move each of the selected stones strength. I made a loop, which establish that the position was compared on the x axis before applying the force (b.state.pos [0]) and after applying the force position (g.state.pos [0])

It does not work well, they are always the same ... I think it's because the new position is not updated after applying increasing force fx=fx+0.01

Any idea to achieve my goal?
Thank you very much,
Laura.

The code:

from yade import pack, qt, plot, export
import numpy as np

##****************************************************************************************************
####### MATERIAL
##****************************************************************************************************

Mat2=O.materials.append(FrictMat(
 young=27e9,poisson=0.30,density=4400,
 frictionAngle=0.7))

##****************************************************************************************************
####### LOAD GRANULAR BED
##****************************************************************************************************

O.load('/home/.../...yade')

##****************************************************************************************************
####### ENGINES
##****************************************************************************************************

O.engines=[
 ForceResetter(),
 InsertionSortCollider(
  [Bo1_Sphere_Aabb(),
   Bo1_Facet_Aabb(),
   Bo1_Box_Aabb(),
   Bo1_Wall_Aabb()]),
 InteractionLoop(
  [Ig2_Sphere_Sphere_ScGeom(),
   Ig2_Facet_Sphere_ScGeom(),
   Ig2_Wall_Sphere_ScGeom(),
   Ig2_Box_Sphere_ScGeom()],
  [Ip2_FrictMat_FrictMat_FrictPhys()],
  [Law2_ScGeom_FrictPhys_CundallStrack()]
 ),
 PyRunner(command='DetermineForceRequired()',
  iterPeriod=1 ,initRun=True,label='checker'),
 NewtonIntegrator(damping=0.5,gravity=(0,-9.81,0),label='newton')
]
O.dt=utils.PWaveTimeStep()

##****************************************************************************************************
####### DETERMINATION OF THE FORCE NEEDED TO MOVE EACH CLUMP
##****************************************************************************************************

def DetermineForceRequired():
 xmax=0.9
 xmin=0.1
 zmax=1.335
 zmin=0.1
 yPOSITION=0.25
 clumpsIds=[] #array to store the identity of certain Clumps

 volumen=[]
 density=2700

 ArrayALLclumps=[]
 ArrayRiddle=[]
 arrayFORCE=[]
 arrayRESULTS=[]

 for i in range(0,len(O.bodies)):
  if O.bodies[i].isClump==True and xmin<O.bodies[i].state.pos[0]<xmax and zmin<O.bodies[i].state.pos[2]<zmax:
   clumpsIds.append(O.bodies[i].clumpId)

 for ii in clumpsIds:
  b=O.bodies[ii]
  if b.state.pos[1]>yPOSITION:

   #...
   #Code to get the area of ​​the clumps
   #...

   peso=b.state.mass
   vol=b.state.mass/density
   volumen.append([vol])
   id_ball=ii
   AREA=areaP/areaM
   Diameter=vol/areaM

   ArrayALLclumps.append([areaP,ii,peso,Diameter,AREA,areaM,b.state.pos[0]])
   np.savetxt('ALL_CLUMPS.out',ArrayALLclumps,delimiter=',')

   if AREA>0.5:

    ArrayRiddle.append([ii,AREA,areaP,peso,Diameter,b.state.pos[0]])
    np.savetxt('Riddle.out',ArrayRiddle,delimiter=',')

    for ll in range(0,len(ArrayRiddle)):

     g=O.bodies[ArrayRiddle[ll][0]]

     for mm in g.shape.members.keys():
      CHANGEcolor=O.bodies[mm]
      CHANGEcolor.shape.color=Vector3(ArrayRiddle[ll][2],0,1)
     fx=0.01
     fy=0
     fz=0
     O.forces.addF(ArrayRiddle[ll][0],(fx,fy,fz))

     arrayFORCE.append([ArrayRiddle[ll][0],fx,g.state.pos[0]])
     np.savetxt('arrayFORCE.out',arrayFORCE,delimiter=',')

     while b.state.pos[0]==g.state.pos[0]: #How I can update the new position to exit the loop?
      fx=fx+0.01
      fy=0
      fz=0
      O.forces.addF(ArrayRiddle[ll][0],(fx,fy,fz))
      number=fx/Diameter

      arrayRESULTS.append([ArrayRiddle[ll][0],number,fx,g.state.pos[0]])
      np.savetxt('RESULTS.out',arrayRESULTS,delimiter=',')

   ######--> Set value to zero before proceeding to the next clump

   areaM=0
   areaP=0
   fx=0
   number=0

Revision history for this message
Jérôme Duriez (jduriez) said :
#6

Hi,

One side note to help you a little to progress towards your goal :

The only thing in your script that moves the bodies / changes their position is the engine NewtonIntegrator (that's its own job). Until this Engine executes (which will be the case after, and then "outside" your python operations of DetermineForceRequired()), positions never change.

So, you have to change the design of your operations.

In case you would think to moye yourself bodies position (changing b.state.pos is possible), this is not really recommanded since contact laws rely on bodies velocities. And, outside NewtonIntegrator, velocities and positions are not related in the binary world of Yade.

Jérôme

Revision history for this message
rayolau (rayolau88) said :
#7

Hi Jérôme, thanks for answering so fast!

I understood that I put inside the while loop, the engine NewtonIntegrator for the positions and velocities are updated. I've updated this part of the code, and I still have the same problem, the position is not updated after applying force.

while b.state.pos[0]!=g.state.pos[0]:
      fx=fx+0.01
      fy=0
      fz=0

      O.engines=[
       InsertionSortCollider(
        [Bo1_Sphere_Aabb(),
         Bo1_Facet_Aabb(),
         Bo1_Box_Aabb(),
         Bo1_Wall_Aabb()]),
       InteractionLoop(
        [Ig2_Sphere_Sphere_ScGeom(),
         Ig2_Facet_Sphere_ScGeom(),
         Ig2_Wall_Sphere_ScGeom(),
         Ig2_Box_Sphere_ScGeom()],
        [Ip2_FrictMat_FrictMat_FrictPhys()],
        [Law2_ScGeom_FrictPhys_CundallStrack()]
       ),
       NewtonIntegrator(damping=0.5,gravity=(0,-9.81,0),label='newton')
      ]

Revision history for this message
Bruno Chareyre (bruno-chareyre) said :
#8

I would suggest to try a much simpler test case. E.g. try to move just
one spherical particle in a granular bed.
The problems are mostly conceptual it seems, but they are hidden into a
complex script.

Revision history for this message
Jérôme Duriez (jduriez) said :
#9

Side note about your answer #7. It seems to me that you modified your DetermineForceRequired() (called periodically through PyRunner), inserting this new § that redefines O.engines

In case I'm right, this would be in my opinion completely a mess, and probably not a solution to your problem. See e.g. https://www.yade-dem.org/doc/user.html#base-engines if the meaning of O.engines is not completely clear to you. Otherwise you may disregard this answer. In all cases, focusing on Bruno's suggestion will certainly help.

Revision history for this message
Jan Stránský (honzik) said :
#10

Hi Laura,

sorry for the late answer..

you have to make order in your variables :-) some functions take as an
argument body ID (like O.forces,addF), and sometimes you need body itself
(like to access b.state). If you are not sure, you can use just the IDs
(numbers), anw if you need body itself, you can always do O.bodies[someID].

If you stil have problems, let us know

cheers
Jan

2014-07-11 11:32 GMT+02:00 rayolau <email address hidden>:

> Question #251510 on Yade changed:
> https://answers.launchpad.net/yade/+question/251510
>
> rayolau posted a new comment:
>
> I tried what you said, and I still got to keep an array containing the
> needed to move each of the particles applied force. Thanks for the
> interest, I'll keep trying. If you need to explain better what I'm doing to
> help, ask what you need!
>
> Thank you for the answers =)
> Laura
>
> ---------------------------------------------------------------------------
> NameError Traceback (most recent call last)
> /usr/bin/yadedaily in <module>()
>
> /usr/bin/yadedaily in identificacion()
> 221 xforce=0
> 222 for xx in range(0,len(array1)):
> --> 223 id_clump=clump.id
> 224 clump.id=O.bodies[array1[xx][0]]
> 225 xforce=xforce+0.001
>
> NameError: global name 'clump' is not defined
>
> --
> You received this question notification because you are a member of
> yade-users, which is an answer contact for Yade.
>
> _______________________________________________
> Mailing list: https://launchpad.net/~yade-users
> Post to : <email address hidden>
> Unsubscribe : https://launchpad.net/~yade-users
> More help : https://help.launchpad.net/ListHelp
>

Revision history for this message
Jan Stránský (honzik) said :
#11

Hi Laura,

after you apply the force, you should IMO let the simulation run a bit
instead of checking the position right after the force application (as said
by others, even without any motion)

you can do something like this:

O.engines = [...whatever, but defined just once! ]

...
applyForceOnSpecificBody()
O.run(100,True)
checkThisBodyAfterSomeSimulationSteps()

is this what you would like to achieve?

cheers
Jan

2014-07-22 9:22 GMT+02:00 Jérôme Duriez <
<email address hidden>>:

> Question #251510 on Yade changed:
> https://answers.launchpad.net/yade/+question/251510
>
> Jérôme Duriez proposed the following answer:
> Side note about your answer #7. It seems to me that you modified your
> DetermineForceRequired() (called periodically through PyRunner),
> inserting this new § that redefines O.engines
>
> In case I'm right, this would be in my opinion completely a mess, and
> probably not a solution to your problem. See e.g. https://www.yade-
> dem.org/doc/user.html#base-engines if the meaning of O.engines is not
> completely clear to you. Otherwise you may disregard this answer. In all
> cases, focusing on Bruno's suggestion will certainly help.
>
> --
> You received this question notification because you are a member of
> yade-users, which is an answer contact for Yade.
>
> _______________________________________________
> Mailing list: https://launchpad.net/~yade-users
> Post to : <email address hidden>
> Unsubscribe : https://launchpad.net/~yade-users
> More help : https://help.launchpad.net/ListHelp
>

Can you help with this problem?

Provide an answer of your own, or ask rayolau for more information if necessary.

To post a message you must log in.