KeyError

Asked by nobody on 2019-10-17

Hi All,

I'm trying to do a gravity deposit and record the contact information. For example, normal contact force for every particle.

I write the code like this:

###########################
import numpy as np
from yade import pack, plot, export, utils
import math
O.bodies.append(geom.facetBox((.5,.5,.5),(.5,.5,.5),wallMask=31))
sp=pack.SpherePack()
sp.makeCloud((0,0,0),(1,1,1),rMean=.04,rRelFuzz=.5)
sp.toSimulation()
O.engines=[
 ForceResetter(),
 InsertionSortCollider([Bo1_Sphere_Aabb(),Bo1_Facet_Aabb()]),
 InteractionLoop(
  [Ig2_Sphere_Sphere_ScGeom(),Ig2_Facet_Sphere_ScGeom()],
  [Ip2_FrictMat_FrictMat_FrictPhys()],
  [Law2_ScGeom_FrictPhys_CundallStrack()]
 ),
 PyRunner(command='checkUnbalanced()',realPeriod=1000),
 PyRunner(command='contact_info()',iterPeriod=1000),
 NewtonIntegrator(gravity=(0,0,-9.81),damping=0.4),
]
O.dt=.5*PWaveTimeStep()
print(len(O.bodies))
def checkUnbalanced():
 if unbalancedForce()<.001:
  O.pause()
d = 0
def contact_info():
 global d
 fn_normals_cal_1 = []
 for i in O.interactions:
  if not i.isReal:continue
  if isinstance(O.bodies[i.id1].shape,Sphere) and isinstance(O.bodies[i.id2].shape,Sphere):
   fn_normal_cal_1 = i.phys.normalForce[0]
   fn_normals_cal_1.append(fn_normal_cal_1)
  plot.reset()
  h = 0
     n = len(fn_normals_cal_1)
     while h < n:
         plot.addData(e_e_e = fn_normals_cal_1[h])
         h = h+1
 plot.saveDataTxt('./contact_info'+str(d)+'.txt',vars = ('e_e_e'))
     d = d+1
O.run(10000,True)
####################
the error is:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "rotation_awn.py", line 40, in contact_info
    plot.saveDataTxt('./contact_info'+str(d)+'.txt',vars = ('e_e_e'))
  File "/packages/7x/yade/2018.02b/lib64/yade-2018.02b/py/yade/plot.py", line 642, in saveDataTxt
    for i in range(len(data[vars[0]])):
KeyError: 'e'

###############

when I changed these lines:

     while h < n:
         plot.addData(e = fn_normals_cal_1[h])
         h = h+1
 plot.saveDataTxt('./contact_info'+str(d)+'.txt',vars = ('e'))
     d = d+1

###### the code works very well.

Is there any special format for vars or something wrong with the code?

best,
yong

Question information

Language:
English Edit question
Status:
Answered
For:
Yade Edit question
Assignee:
No assignee Edit question
Last query:
2019-10-18
Last reply:
2019-10-20
Jan Stránský (honzik) said : #1

Hi,

> plot.saveDataTxt('./contact_info'+str(d)+'.txt',vars = ('e_e_e'))

here, the parentheses around ('e_e_e') has no effect and than the code is equal to
vars='e_e_e'
which is interpreted as ('e','_','e','_','e'), the original string split to letters.

Use
vars=['e_e_e'] # list, no comma needed (see below)
or
vars=('e_e_e',) # note the comma, this way it is a tuple with 1 element

cheers
Jan

nobody (nobody01) said : #2

Hi Jan,

I tried what you said, this works fine.

But if I load a sample, like this: O.load ('sample.yade.gz')

If I want to record several variables.

the sample is just the gravity deposition.[1]
and then I use the same code as I mention yesterday.
#######################################
O.load ('sample.yade.gz')
from yade import geom
import itertools
from numpy import *
import numpy as np
from yade import pack, plot, export, utils
import math
def checkUnbalanced():
 if unbalancedForce()<.001:
  O.pause()
O.engines=[
 ForceResetter(),
 InsertionSortCollider([Bo1_Sphere_Aabb(),Bo1_Facet_Aabb()]),
 InteractionLoop(
   [Ig2_Sphere_Sphere_ScGeom6D(),Ig2_Facet_Sphere_ScGeom()],
   [Ip2_FrictMat_FrictMat_FrictPhys(),Ip2_CohFrictMat_CohFrictMat_CohFrictPhys()], [Law2_ScGeom_FrictPhys_CundallStrack(),Law2_ScGeom6D_CohFrictPhys_CohesionMoment(useIncrementalForm=True,always_use_moment_law=True,label='cohesiveLaw')]
 ),
 GlobalStiffnessTimeStepper(active=1,timeStepUpdateInterval=10000,timestepSafetyCoefficient=0.8),
 NewtonIntegrator(gravity=(0,0,-9.81),damping=0.4),
 PyRunner(command='contact_info()',iterPeriod=1000),
]
d = 0
def contact_info():
 global d
 fn_normals_cal_1 = []
 fn_normals_cal_2 = []
 fn_normals_cal_3 = []
 for i in O.interactions:
  if not i.isReal:continue
  if isinstance(O.bodies[i.id1].shape,Sphere) and isinstance(O.bodies[i.id2].shape,Sphere):
   fn_normal_cal_1 = i.phys.normalForce[0]
   fn_normal_cal_2 = i.phys.normalForce[1]
   fn_normal_cal_3 = i.phys.normalForce[2]
   fn_normals_cal_1.append(fn_normal_cal_1)
   fn_normals_cal_2.append(fn_normal_cal_2)
   fn_normals_cal_3.append(fn_normal_cal_3)
  plot.reset()
  h = 0
    n = len(fn_normals_cal_1)
    while h < n:
        plot.addData(x = fn_normals_cal_1[h],y = fn_normals_cal_2[h],z= fn_normals_cal_3[h])
        h = h+1
 plot.saveDataTxt('./contact_info'+str(d)+'.txt',vars = ('x','y','z'))
    d = d+1
O.run(10000000,True)

I think this time the variables' format is correct.

but when I ran this code.

I still got the same problem.
#############################
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "rotation_awn.py", line 60, in contact_info
    plot.saveDataTxt('./contact_info'+str(d)+'.txt',vars = ('x','y','z'))
  File "/packages/7x/yade/2018.02b/lib64/yade-2018.02b/py/yade/plot.py", line 642, in saveDataTxt
    for i in range(len(data[vars[0]])):
KeyError: 'x'
###############################

If I didn't save the sample and reload it.

I just run the gravity deposition and record the data, I didn't get any errors.

##########
By the way, I did all these processes under same computer. so this is not related to different versions of YADE and computer.

So, I'm thinking this is related to the O.save and O.load problem? or because I did something wrong with the recorder?

best,
yong

[1] https://yade-dem.org/doc/tutorial-examples.html#gravity-deposition

Jan Stránský (honzik) said : #3

> So, I'm thinking this is related to the O.save and O.load problem?

yes, O.save / O.load only treat C++ stuff, yade.plot is purely Python stuff and it is not saved nor loaded.
Depending on what you want with plot.data, you can:
- save / load the plot.data dictionary at the time of with O.save / O.load. (if you want previous data to be preserved)
- just continue running and call plot.saveDataTxt at a time when it is not empty (if the previous data are not important or you are happy with having them in 2 files)
- ...

cheers
Jan

nobody (nobody01) said : #4

Hi Jan,
So the only way to resolve this error is not to use the O.save and O.load?

how about my sample number is really huge, I can not make the sample every time.

can I use the yade.export.text command to save the position of all the particles and use yade.ymport.text to reload the position of the particles. which will assume that the particles are generated just at the position at first.

best,
yong

Jan Stránský (honzik) said : #5

> So the only way to resolve this error is not to use the O.save and O.load?

no, what I meant is not only using O.save/O.load, but save/load plot.data, something like:

### script 1
import json
from yade import plot
O.bodies.append(sphere((0,0,0),1))
newton.gravity = (0,0,-10)
O.engines += [PyRunner(iterPeriod=1,command="plot.addData(v=O.bodies[0].state.vel)")]
O.run(5,True)
O.save("s1.yade.gz")
with open("s1.json","w") as f:
 json.dump(plot.data,f)
###

### script 2
import json
from yade import plot
O.load("s1.yade.gz")
with open("s1.json") as f:
 plot.data = json.load(f)
O.run(5,True)
print(plot.data)
###

> can I use the yade.export.text command to save the position of all the particles and use yade.ymport.text to reload the position of the particles.

yes, of course.
O.save / O.load saves and loads all the scene (materials, velocities, engines, ...).
So it depends on specific situation which approach to prefer..

cheers
Jan

Can you help with this problem?

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

To post a message you must log in.