Skip to content

Latest commit

 

History

History

sphere

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

sphere.diderot: Mutually-repelling particles populating a unit sphere

This is heavily based on the circle.diderot example; see that program for more detailed and explanatory comments. The new things added with this example are documented in comments below. A significant capability demonstrated here is "population control", whereby particles create new particles (using new) if there seem to be too few, or die if there are too may (using die). Along with this there is a new variable undone that acts as a crude signal (to the global update method monitoring the computation) that things are unfinished because the system population is changing.

Like the circle.diderot example, we use snapshots to inspect the system state as it progresses, and compile with --double for better precision:

diderotc --snapshot --double --exec sphere.diderot

The following creates a list of N randomly oriented unit-length 3-vectors in vec3.nrrd which will be the initial input. Setting the random number seed of unu 1op nrand with -s RNG ensures reproducible results, or you can leave that out to give different results each time.

N=2
RNG=1
echo 0 0 0 | unu pad -min 0 0 -max M $((N-1)) | unu 1op nrand -s $RNG -o vec3.nrrd
unu project -i vec3.nrrd -a 0 -m l2 | unu axinsert -a 0 -s 3 | unu 2op / vec3.nrrd - -o vec3.nrrd

Then to run with snapshots saved every iteration (-s 1), but limiting the program to 400 iterations (-l 400), as well as cleaning results from previous run:

rm -f pos-????.{png,nrrd} pos.nrrd
./sphere -s 1 -l 400 -rad 0.15 -eps 0.033 -pcp 2

This should converge in under 500 iterations, many pos-????.nrrd files. The interaction radius -rad 0.15 can be decreased to create a denser (though more computationally expensive) result; increasing it makes it sparser. The following unu hackery processes this into corresponding pos-????.png images. The images are 2*SZ by SZ, computed as a joint histogram of coordinates, with oversampling OV (higher values improves anti-aliasing).

SZ=350
OV=2
export NRRD_STATE_VERBOSE_IO=0
for PIIN in pos-????.nrrd; do
   IIN=${PIIN#*-}
   II=${IIN%.*}
   echo "post-processing $PIIN to pos-$II.png ... "
   unu dice -i $PIIN -a 0 -o ./
   unu 2op gt 2.nrrd 0 | # 1 if in lower hemisphere
   unu 2op x - 2.1 |     # 2.1 if in lower hemisphere
   unu 2op + - 0.nrrd |  # add to x component
   unu jhisto -i - 1.nrrd -min -1.05 -1.05 -max 3.15 1.05 -b $((OV*SZ*2)) $((SZ*OV)) |
   unu resample -s /$OV /$OV -k bspln5 -t float |
   unu quantize -b 8 -min 0 -max $(echo "0.15 / ($OV * $OV)" | bc -l) -o pos-$II.png
done
rm -f {0,1,2}.nrrd

Note that while we are post-processing results after the computation is finished, these snapshots are produced while the computation is running. When compiling Diderot programs to a library, the API makes the snapshots available between iterations. Also, the sort of unu hacking used above is not actually a required part of using Diderot; the aim here is just to producing something informative with the minimal number of software tools. For fun we make an animated GIF of the results with ImageMagick's convert:

convert -delay 6 pos*.png sphere-spread.gif

The resulting sphere-spread.gif (c.f. ref-sphere-spread.gif) shows how the population control worked to go from 2 to hundreds of particles. On the other hand, if the initial data commands above had started with N=8000, the resulting animation sphere-decim.gif (c.f. ref-sphere-decim.gif) shows how the system responds to starting with too many particles, by decimating the population to arive at roughly the same number of points as when starting with N=2.