Yade 2019.01a vs. gitlab version

Asked by Bettina Suhr on 2019-08-27

Dear all,

until now, I used Yade 2019.01a for my computations. Recently, I also downloaded and installed the current version from gitlab. When I compare the results obtained from both versions, I see (small) differences. I’m a bit worried, because I do not see such differences between Yade 2018.02b and Yade 2019.01a.

An example for the obtained differences can be seen in the 03-oedometric-test.py script. I added “seed=1” in the makeCloud command and obtain identical initial positions for the spheres (wrt. yade version). The particles settle under gravity. When the unbalanced force is below 0.1, a plate is inserted for compression. The position of the plate is above the highest sphere in the packing and already here there are differences (note: I changed the PyRunner iterPeriod for a better comparison: PyRunner(command='checkUnbalanced()',iterPeriod=100,label='checker') )

#add plate at position: 0.549239607153 at iteration: 10300 # Yade 2018.02b
#add plate at position: 0.549239607153 at iteration: 10300 # Yade 2019.01a
#add plate at position: 0.575951497648 at iteration: 9800# yade gitlab compiled with Python 2
#add plate at position: 0.5759514976482029 at iteration: 9800# yade gitlab compiled with Python 3

For backward compatibility, I think it’s worth investigating, what causes these changes. Do you agree?
Do you have any suggestion, how I can track these changes down?

Thanks and best regards,
Bettina

Question information

Language:
English Edit question
Status:
Answered
For:
Yade Edit question
Assignee:
No assignee Edit question
Last query:
2019-08-29
Last reply:
2019-08-29

Hi Bettina,

> Do you agree?

Yes!
Thanks for reporting.

I suspect a change done recently in order to make results *more reproducible* [1], especially with multithreaded (-jN) runs.
But of course it introduces a difference between older and newer results (they are all equally correct, though). It appeared in the master branch in June, so if you could compare 7a4a71ef (after change) to 900c7616 (before) it could confirm that.

If it doesn't:
- Could you paste here the exact script you are using, so everyone can reproduce the "#add plate..." messages?

Suggestions:
- are timesteps the same?
- are all positions exactly the same at iteration 0, then 1? (you can just sum all positions together and compare the result to make it simpler)

Cheers

Bruno

[1] https://gitlab.com/yade-dev/trunk/commit/68d600d283914d74693cd42ed0b0eb89eefa3c98

Unlike what the commit message suggests most of the reproducibility is obtained even if loopOnSortedInteractions=False.

Bettina Suhr (bettina-suhr) said : #2

Dear Bruno,

Thanks a lot for your answer and your suggestions.

The time steps are the same as well as the initial positions of the spheres.

Due to some technical difficulties it may take some days until I can compare the two commits, which you mentioned. I will post the results then.

Best regards,
Bettina

Bettina Suhr (bettina-suhr) said : #3

Dear all,

I tried to do the checks, which Bruno suggested, but I didn’t succeed.
After checking out the commit 900c7616, running cmake and make clean, I get an error in compilation:

/home/bettinasuhr/yade-gitlab/trunk/pkg/common/InsertionSortCollider.cpp:526:22: error: invalid use of member function ‘size_t InsertionSortCollider::VecBounds::size() const’ (did you forget the ‘()’ ?)
    for(long i=0; i<V.size; i++){
                    ~~^~~~
CMakeFiles/yade.dir/build.make:504: recipe for target 'CMakeFiles/yade.dir/pkg/common/InsertionSortCollider.cpp.o' failed
make[2]: *** [CMakeFiles/yade.dir/pkg/common/InsertionSortCollider.cpp.o] Error 1
CMakeFiles/Makefile2:142: recipe for target 'CMakeFiles/yade.dir/all' failed
make[1]: *** [CMakeFiles/yade.dir/all] Error 2
Makefile:129: recipe for target 'all' failed
make: *** [all] Error 2

Did I do something wrong? This looks to me like a typo in the code of InsertionSortCollider.cpp

If somebody can run these tests easier than me, below is the script, which I used to obtain the results posted above.

Thanks and regards,
Bettina

# gravity deposition, continuing with oedometric test after stabilization
# shows also how to run parametric studies with yade-batch

# The components of the batch are:
# 1. table with parameters, one set of parameters per line (ccc.table)
# 2. readParamsFromTable which reads respective line from the parameter file
# 3. the simulation muse be run using yade-batch, not yade
#
# $ yade-batch --job-threads=1 03-oedometric-test.table 03-oedometric-test.py
#

# load parameters from file if run in batch
# default values are used if not run from batch
readParamsFromTable(rMean=.05,rRelFuzz=.3,maxLoad=1e6,minLoad=1e4)
# make rMean, rRelFuzz, maxLoad accessible directly as variables later
from yade.params.table import *
from yade import export,ymport

# create box with free top, and ceate loose packing inside the box
from yade import pack, plot
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=rMean,rRelFuzz=rRelFuzz, seed=1)
sp.toSimulation()
export.text('INITIAL.txt')

O.engines=[
 ForceResetter(),
 # sphere, facet, wall
 InsertionSortCollider([Bo1_Sphere_Aabb(),Bo1_Facet_Aabb(),Bo1_Wall_Aabb()]),
 InteractionLoop(
  # the loading plate is a wall, we need to handle sphere+sphere, sphere+facet, sphere+wall
  [Ig2_Sphere_Sphere_ScGeom(),Ig2_Facet_Sphere_ScGeom(),Ig2_Wall_Sphere_ScGeom()],
  [Ip2_FrictMat_FrictMat_FrictPhys()],
  [Law2_ScGeom_FrictPhys_CundallStrack()]
 ),
 NewtonIntegrator(gravity=(0,0,-9.81),damping=0.5),
 # the label creates an automatic variable referring to this engine
 # we use it below to change its attributes from the functions called
 PyRunner(command='checkUnbalanced()',iterPeriod=100,label='checker'),
]
O.dt=.5*PWaveTimeStep()

# the following checkUnbalanced, unloadPlate and stopUnloading functions are all called by the 'checker'
# (the last engine) one after another; this sequence defines progression of different stages of the
# simulation, as each of the functions, when the condition is satisfied, updates 'checker' to call
# the next function when it is run from within the simulation next time

# check whether the gravity deposition has already finished
# if so, add wall on the top of the packing and start the oedometric test
def checkUnbalanced():
 # at the very start, unbalanced force can be low as there is only few contacts, but it does not mean the packing is stable
 #print (O.iter, unbalancedForce())
 if O.iter<5000: return
 # the rest will be run only if unbalanced is < .1 (stabilized packing)
 if unbalancedForce()>.1: return
 # add plate at the position on the top of the packing
 # the maximum finds the z-coordinate of the top of the topmost particle
 print ('add plate at position: ', max([b.state.pos[2]+b.shape.radius for b in O.bodies if isinstance(b.shape,Sphere)]) ,'at iteration: ', O.iter)
 O.bodies.append(wall(max([b.state.pos[2]+b.shape.radius for b in O.bodies if isinstance(b.shape,Sphere)]),axis=2,sense=-1))
 global plate # without this line, the plate variable would only exist inside this function
 plate=O.bodies[-1] # the last particles is the plate
 # Wall objects are "fixed" by default, i.e. not subject to forces
 # prescribing a velocity will therefore make it move at constant velocity (downwards)
 plate.state.vel=(0,0,-.1)
 # start plotting the data now, it was not interesting before
 O.engines=O.engines+[PyRunner(command='addPlotData()',iterPeriod=200)]
 # next time, do not call this function anymore, but the next one (unloadPlate) instead
 checker.command='unloadPlate()'

def unloadPlate():
 # if the force on plate exceeds maximum load, start unloading
 if abs(O.forces.f(plate.id)[2])>maxLoad:
  plate.state.vel*=-1
  # next time, do not call this function anymore, but the next one (stopUnloading) instead
  checker.command='stopUnloading()'

def stopUnloading():
 if abs(O.forces.f(plate.id)[2])<minLoad:
  # O.tags can be used to retrieve unique identifiers of the simulation
  # if running in batch, subsequent simulation would overwrite each other's output files otherwise
  # d (or description) is simulation description (composed of parameter values)
  # while the id is composed of time and process number
  plot.saveDataTxt('resultsOedometric'+O.tags['d.id']+'.txt')
  O.pause()

def addPlotData():
 if not isinstance(O.bodies[-1].shape,Wall):
  plot.addData(); return
 Fz=O.forces.f(plate.id)[2]
 plot.addData(Fz=Fz,w=plate.state.pos[2]-plate.state.refPos[2],unbalanced=unbalancedForce(),i=O.iter)

# besides unbalanced force evolution, also plot the displacement-force diagram
plot.plots={'i':('unbalanced',),'w':('Fz',)}
plot.plot()

O.run()

# when running with yade-batch, the script must not finish until the simulation is done fully
# this command will wait for that (has no influence in the non-batch mode)
waitIfBatch()

Thanks for trying. Maybe there was indeed a typo in that specific commit and it was fixed in another one. Unfortunately I don't think I'll manage to try it very soon. For now I would say there is no reason to panic, most likely the situation with latest versions is ok, but it would be worth verifying.
Bruno

Can you help with this problem?

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

To post a message you must log in.