commit cd4e192c01d957b17d2ff205151b214458f1961b
parent 22209caf17f3edd5bdf18ce66a2570d9e0cc50ed
Author: Anders Damsgaard <andersd@riseup.net>
Date: Wed, 8 Nov 2017 11:37:29 -0500
add sedimentation example, fix render command by removing import
Diffstat:
3 files changed, 182 insertions(+), 6 deletions(-)
diff --git a/docs/src/man/getting_started.md b/docs/src/man/getting_started.md
@@ -20,7 +20,7 @@ name>`. An example:
```julia-repl
julia> ?Granular.fitGridToGrains!
- fitGridToGrains!(simulation, grid[, padding])
+ fitGridToGrains!(simulation, grid[, padding, verbose])
Fit the ocean or atmosphere grid for a simulation to the current grains and their positions.
@@ -38,7 +38,7 @@ julia> ?Granular.fitGridToGrains!
```
## Collision between two particles
-For this simple example (`example/two-grains.jl`), we will create two grains,
+For this simple example (`examples/two-grains.jl`), we will create two grains,
where one of the grains is bumping in to the other.
As the first command, we import all the Granular.jl functionality:
@@ -243,6 +243,12 @@ chosen parameter under the *Glyph1* object in the *Pipeline Browser* on the
left, and selecting a different field for *Coloring*. Press the *Apply* button
to see the changes in effect.
+**Tip:** If you have the command `pvpython` (ParaView Python) available from
+the command line, you can visualize the simulation directly from the command
+line without entering ParaView by the command `sim.render()`. Furthermore, if
+you have the `convert` command from ImageMagick installed (`brew install
+imagemagick` on macOS), the output images will be merged into an animated GIF.
+
### Exercises
To gain more familiarity with the simulation procedure, I suggest experimenting
with the following:
@@ -256,3 +262,136 @@ with the following:
affected by the choice of time step length? Try setting different time
step values, e.g. with `sim.time_step = 0.1234` and rerun the simulation.
+## Sedimentation of grains
+Grains are known to settle under gravitation in water according to *Stoke's
+law*, where resistive drag acts opposite of gravity and with a magnitude
+according to the squareroot of velocity difference between water and grain.
+
+Granular.jl offers simple fluid grids with prescribed velocity fields, and the
+grains are met with drag in this grid.
+
+In this example (`examples/sedimentation.jl`) we will initialize a range of
+grain sizes in a loose configuration, add gravity and a surrounding fluid grid,
+and let the grains settle towards the bottom.
+
+As in the previous example, we start by creating a fluid grid:
+
+```julia-repl
+julia> import Granular
+julia> sim = Granular.createSimulation(id="sedimentation.jl")
+```
+
+### Creating a pseudo-random grain packing
+Instead of manually adding grains one by one, we can use the
+`regularPacking!()` function to add a regular grid of random-sized grains to
+the simulation. Below, we specify that we want the grid of grains to be 10
+grains wide along x, and 50 grains tall along y. We also specify the grain
+radii to fall between 0.02 and 0.2 m. The sizes will be drawn from a power-law
+distribution, by default.
+
+```julia-repl
+julia> Granular.regularPacking!(sim, [10, 50], 0.02, 0.2)
+```
+
+Since we haven't explicitly set the grain sizes for this example, we can
+inspect the values by plotting a histogram of sizes:
+
+```julia-repl
+julia> Granular.plotGrainSizeDistribution(sim)
+INFO: sedimentation-grain-size-distribution.png
+```
+
+The output informs us that we have the plot saved as an image with the file
+name `sedimentation-grain-size-distribution.png`.
+
+### Creating a fluid grid
+We can now create a fluid (ocean) grid spanning the extent of the grains
+created above:
+
+```julia-repl
+julia> Granular.fitGridToGrains!(sim, sim.ocean)
+```
+
+We want the boundaries of the above grid to be impermeable for the grains, so
+they stack up at the bottom. Granular.jl acknowledges the boundary types with
+a confirmation message:
+
+```julia-repl
+julia> Granular.setGridBoundaryConditions!(sim.ocean, "impermeable")
+West (-x): impermeable (3)
+East (+x): impermeable (3)
+South (-y): impermeable (3)
+North (+y): impermeable (3)
+```
+
+### Adding gravitational acceleration
+If we started the simulation now, nothing would happen as gravity is disabled
+by default. We can enable gravitational acceleration as a constant body force
+for each grain (`Force = mass * acceleration`):
+
+```julia-repl
+julia> g = [0.0, -9.8];
+julia> for grain in sim.grains
+ Granular.addBodyForce!(grain, grain.mass*g)
+ end
+```
+
+### Setting temporal parameters
+As before, we ask the code to select a suitable computational time step based
+on grain sizes and properties:
+
+```julia-repl
+julia> Granular.setTimeStep!(sim)
+INFO: Time step length t=1.6995699879716792e-5 s
+```
+
+We also again set the total simulation time as well as the output file
+interval:
+
+```julia-repl
+julia> Granular.setTotalTime!(sim, 5.0)
+julia> Granular.setOutputFileInterval!(sim, 0.2)
+```
+
+### Running the simulation
+We are now ready to run the simulation:
+
+```julia-repl
+julia> Granular.run!(sim)
+INFO: Output file: ./sedimentation/sedimentation.grains.1.vtu
+INFO: Output file: ./sedimentation/sedimentation.ocean.1.vts
+INFO: wrote status to ./sedimentation/sedimentation.status.txt
+ t = 0.19884968859273294/5.0 s
+INFO: Output file: ./sedimentation/sedimentation.grains.2.vtu
+INFO: Output file: ./sedimentation/sedimentation.ocean.2.vts
+INFO: wrote status to ./sedimentation/sedimentation.status.txt
+ t = 0.3993989471735396/5.0 s
+
+...
+
+INFO: Output file: ./sedimentation/sedimentation.grains.25.vtu
+INFO: Output file: ./sedimentation/sedimentation.ocean.25.vts
+INFO: wrote status to ./sedimentation/sedimentation.status.txt
+ t = 4.998435334626701/5.0 s
+INFO: ./sedimentation/sedimentation.py written, execute with 'pvpython /Users/ad/code/Granular-ext/examples/sedimentation/sedimentation.py'
+INFO: wrote status to ./sedimentation/sedimentation.status.txt
+ t = 5.00001593471549/5.0 s
+```
+
+The output can be plotted in ParaView as discribed in the `two-grain` example
+above, or, if `pvpython` is available from the command line, directly from
+Julia with the following command:
+
+```julia-repl
+julia> Granular.render(sim, trim=false)
+```
+
+### Exercises
+- How are the granular contact pressures distributed in the final result?
+- Try running the above example, but without fluid drag. Disable the drag by
+ including the call `Granlar.disableOceanDrag!(grain)` in the `for` loop
+ where gravitational acceleration is set for each grain.
+- How does the range of grain sizes affect the result? Try making all grains
+ bigger or smaller.
+- How is the model performance effected if the grain-size distribution is
+ wide or narrow?
diff --git a/examples/sedimentation.jl b/examples/sedimentation.jl
@@ -0,0 +1,41 @@
+#/usr/bin/env julia
+import Granular
+
+#### Create a loose granular assemblage and let it settle at towards -y
+sim = Granular.createSimulation(id="sedimentation")
+
+# Generate 10 grains along x and 50 grains along y, with radii between 0.2 and
+# 1.0 m.
+Granular.regularPacking!(sim, [10, 50], 0.02, 0.2)
+
+# Visualize the grain-size distribution
+Granular.plotGrainSizeDistribution(sim)
+
+# Create a grid for contact searching spanning the extent of the grains in the
+# simulation
+Granular.fitGridToGrains!(sim, sim.ocean)
+
+# Make the grid boundaries impermeable for the grains, which
+Granular.setGridBoundaryConditions!(sim.ocean, "impermeable")
+
+# Add gravitational acceleration to all grains
+g = [0., -9.8]
+for grain in sim.grains
+ Granular.addBodyForce!(grain, grain.mass*g)
+end
+
+# Automatically set the computational time step based on grain sizes and
+# properties
+Granular.setTimeStep!(sim)
+
+# Set the total simulation time for this step [s]
+Granular.setTotalTime!(sim, 5.0)
+
+# Set the interval in model time between simulation files [s]
+Granular.setOutputFileInterval!(sim, 0.2)
+
+# Start the simulation
+Granular.run!(sim)
+
+# Try to render the simulation if `pvpython` is installed on the system
+Granular.render(sim, trim=false)
diff --git a/src/io.jl b/src/io.jl
@@ -947,10 +947,6 @@ function render(simulation::Simulation; pvpython::String="pvpython",
# use ImageMagick installed with Homebrew.jl if available,
# otherwise search for convert in $PATH
convert = "convert"
- if is_apple()
- import Homebrew
- convert = Homebrew.prefix() * "/bin/convert"
- end
run(`$convert $trim_string +repage -delay 10
-transparent-color white