twall normal must be positive, add wall temporal integration, add more tests - Granular.jl - Julia package for granular dynamics simulation
 (HTM) git clone git://src.adamsgaard.dk/Granular.jl
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 5951464686ab69926cfb9d4905f42ea898d38789
 (DIR) parent f2a496feac2b8cbb587385d9a4068a508a4f832e
 (HTM) Author: Anders Damsgaard <andersd@riseup.net>
       Date:   Wed, 15 Nov 2017 16:02:34 -0500
       
       wall normal must be positive, add wall temporal integration, add more tests
       
       Diffstat:
         M examples/shear.jl                   |       1 -
         M src/datatypes.jl                    |       2 ++
         M src/interaction.jl                  |       7 +------
         M src/temporal_integration.jl         |     120 ++++++++++++++++++++++++++++++-
         M src/wall.jl                         |      37 ++++++++++++++++++++++++++-----
         M test/wall.jl                        |     223 +++++++++++++++++++++++++++++--
       
       6 files changed, 364 insertions(+), 26 deletions(-)
       ---
 (DIR) diff --git a/examples/shear.jl b/examples/shear.jl
       t@@ -16,7 +16,6 @@ const nx = 10
        const ny = 50
        const r_min = 0.2
        const r_max = 1.0
       -const z_thickness = 
        Granular.regularPacking!(sim, [nx, ny], r_min, r_max)
        
        # Create a grid for contact searching spanning the extent of the grains
 (DIR) diff --git a/src/datatypes.jl b/src/datatypes.jl
       t@@ -77,8 +77,10 @@ mutable struct WallLinearFrictionless
            bc::String                # Boundary condition
            mass::Float64             # Mass, used when bc != "fixed"
            thickness::Float64        # Wall thickness
       +    surface_area::Float64     # Wall surface area
            normal_stress::Float64    # Normal stress when bc == "normal stress"
            vel::Float64              # Velocity (constant when bc == "normal stress")
       +    acc::Float64              # Acceleration (zero when bc == "velocity")
            force::Float64            # Sum of normal forces on wall
        end
        
 (DIR) diff --git a/src/interaction.jl b/src/interaction.jl
       t@@ -57,11 +57,6 @@ function interactWalls!(sim::Simulation)
                    δ_n = abs(dot(sim.walls[iw].normal, sim.grains[i].lin_pos) -
                              sim.walls[iw].pos) - sim.grains[i].contact_radius
        
       -            #println(dot(sim.walls[iw].normal, sim.grains[i].lin_pos))
       -            #println(sim.walls[iw].pos)
       -            #println(sim.grains[i].contact_radius)
       -            #println(δ_n)
       -
                    if δ_n < 0.
                        if sim.grains[i].youngs_modulus > 0.
                            k_n = sim.grains[i].youngs_modulus * sim.grains[i].thickness
       t@@ -69,8 +64,8 @@ function interactWalls!(sim::Simulation)
                            k_n = sim.grains[i].contact_stiffness_normal
                        end
        
       -                sim.walls[iw].force += -k_n * δ_n
                        sim.grains[i].force += k_n * abs(δ_n) * sim.walls[iw].normal
       +                sim.walls[iw].force += k_n * δ_n
                    end
                end
            end
 (DIR) diff --git a/src/temporal_integration.jl b/src/temporal_integration.jl
       t@@ -46,7 +46,7 @@ end
        export updateGrainKinematicsTwoTermTaylor!
        """
        Use a two-term Taylor expansion for integrating the kinematic degrees of freedom 
       -for an `grain`.
       +for a `grain`.
        """
        function updateGrainKinematicsTwoTermTaylor!(grain::GrainCylindrical,
                                                       simulation::Simulation)
       t@@ -80,7 +80,7 @@ end
        export updateGrainKinematicsThreeTermTaylor!
        """
        Use a three-term Taylor expansion for integrating the kinematic degrees of 
       -freedom for an `grain`.
       +freedom for a `grain`.
        """
        function updateGrainKinematicsThreeTermTaylor!(grain::GrainCylindrical,
                                                         simulation::Simulation)
       t@@ -122,3 +122,119 @@ function updateGrainKinematicsThreeTermTaylor!(grain::GrainCylindrical,
                0.5 * d_ang_acc_dt * simulation.time_step^2.
            nothing
        end
       +
       +export updateWallKinematics!
       +"""
       +    updateWallKinematics!(simulation::Simulation[,
       +                          method::String = "Three-term Taylor"])
       +
       +Update the wall kinematic parameters using a temporal integration scheme,
       +the current force and torque balance, and gravitational acceleration.  If the
       +simulation contains a grid with periodic boundaries, affected wall positions
       +are adjusted accordingly.
       +
       +# Arguments
       +* `simulation::Simulation`: update the wall positions in this object 
       +    according to temporal integration of length `simulation.time_step`.
       +* `method::String = "Three-term Taylor"`: the integration method to use.  
       +    Available methods are "Two-term Taylor" and "Three-term Taylor".  The 
       +    three-term Taylor expansion is slightly more computationally expensive than 
       +    the two-term Taylor expansion, but offers an order-of-magnitude increase in 
       +    precision of wall positions.  The two-term expansion can obtain similar 
       +    precision if the time step is 1/10 the length.
       +"""
       +function updateWallKinematics!(simulation::Simulation;
       +                                method::String = "Three-term Taylor")
       +
       +    if method == "Two-term Taylor"
       +        for wall in simulation.walls
       +            if wall.bc == "fixed"
       +                continue
       +            end
       +            updateWallKinematicsTwoTermTaylor!(wall, simulation)
       +        end
       +    elseif method == "Three-term Taylor"
       +        for wall in simulation.walls
       +            if wall.bc == "fixed"
       +                continue
       +            end
       +            updateWallKinematicsThreeTermTaylor!(wall, simulation)
       +        end
       +    else
       +        error("Unknown integration method '$method'")
       +    end
       +    nothing
       +end
       +
       +export updateWallKinematicsTwoTermTaylor!
       +"""
       +    updateWallKinematicsTwoTermTaylor!(wall, simulation)
       +
       +Use a two-term Taylor expansion for integrating the kinematic degrees of freedom 
       +for a `wall`.
       +"""
       +function updateWallKinematicsTwoTermTaylor!(wall::WallLinearFrictionless,
       +                                            simulation::Simulation)
       +    if wall.bc == "fixed"
       +        return nothing
       +    end
       +
       +    if wall.bc == "velocity"
       +        wall.acc = 0.0
       +    else
       +        # Normal force directed along normal
       +        f_n::Float64 = -wall.normal_stress*wall.surface_area
       +        wall.acc = (wall.force + f_n)/wall.mass
       +    end
       +
       +    wall.pos +=
       +        wall.vel * simulation.time_step +
       +        0.5*wall.acc * simulation.time_step^2.0
       +
       +    wall.vel += wall.acc * simulation.time_step
       +    nothing
       +end
       +
       +
       +export updateWallKinematicsThreeTermTaylor!
       +"""
       +    updateWallKinematicsThreeTermTaylor!(wall, simulation)
       +
       +Use a two-term Taylor expansion for integrating the kinematic degrees of freedom 
       +for a `wall`.
       +"""
       +function updateWallKinematicsThreeTermTaylor!(wall::WallLinearFrictionless,
       +                                              simulation::Simulation)
       +    if simulation.time_iteration == 0
       +        acc_0 = 0.
       +    else
       +        acc_0 = wall.acc
       +    end
       +
       +    if wall.bc == "fixed"
       +        return nothing
       +    end
       +
       +    # Normal load = normal stress times wall surface area, directed along normal
       +
       +    if wall.bc == "velocity"
       +        wall.acc = 0.0
       +    else
       +        f_n::Float64 = -wall.normal_stress*wall.surface_area
       +        wall.acc = (wall.force + f_n)/wall.mass
       +    end
       +
       +    # Temporal gradient in acceleration using backwards differences
       +    d_acc_dt = (wall.acc - acc_0)/simulation.time_step
       +
       +    wall.pos +=
       +        wall.vel * simulation.time_step +
       +        0.5*wall.acc * simulation.time_step^2.0 +
       +        1.0/6.0 * d_acc_dt * simulation.time_step^3.0
       +
       +    wall.vel += wall.acc * simulation.time_step +
       +        0.5 * d_acc_dt * simulation.time_step^2.0
       +
       +    nothing
       +end
       +
 (DIR) diff --git a/src/wall.jl b/src/wall.jl
       t@@ -3,7 +3,7 @@
        export addWallLinearFrictionless!
        """
            function addWallLinear!(simulation, normal, pos[, bc, mass, thickness, 
       -                            normal_stress, vel, force, verbose])
       +                            normal_stress, vel, acc, force, verbose])
        
        Creates and adds a linear (flat) and frictionless dynamic wall to a grain to a
        simulation. Most of the arguments are optional, and come with default values.
       t@@ -58,7 +58,7 @@ To create a wall parallel to the *y* axis pushing downwards with a constant
        normal stress of 100 kPa, starting at a position of y = 3.5 m:
        
        ```julia
       -Granular.addWallLinearFrictionless!(sim, [0., -1.], 3.5,
       +Granular.addWallLinearFrictionless!(sim, [0., 1.], 3.5,
                                            bc="normal stress",
                                            normal_stress=100e3)
        ```
       t@@ -69,8 +69,10 @@ function addWallLinearFrictionless!(simulation::Simulation,
                                            bc::String = "fixed",
                                            mass::Float64 = NaN,
                                            thickness::Float64 = NaN,
       +                                    surface_area::Float64 = NaN,
                                            normal_stress::Float64 = 0.,
                                            vel::Float64 = 0.,
       +                                    acc::Float64 = 0.,
                                            force::Float64 = 0.,
                                            verbose::Bool=true)
        
       t@@ -80,12 +82,15 @@ function addWallLinearFrictionless!(simulation::Simulation,
                      "$normal)")
            end
        
       -    if !(normal ≈ [1., 0.]) && !(normal ≈ [0., 1.]) &&
       -        !(normal ≈ [-1., 0.]) && !(normal ≈ [0., -1.])
       +    if bc != "fixed" && bc != "velocity" && bc != "normal stress"
       +        error("Wall BC must be 'fixed', 'velocity', or 'normal stress'.")
       +    end
       +
       +    if !(normal ≈ [1., 0.]) && !(normal ≈ [0., 1.])
                error("Currently only walls with normals orthogonal to the " *
                      "coordinate system are allowed, i.e. normals parallel to the " *
                      "x or y axes.  Accepted values for `normal` " *
       -              "are [±1., 0.] and [0., ±1.].  The passed normal was $normal")
       +              "are [1., 0.] and [0., 1.].  The passed normal was $normal")
            end
        
            # if not set, set wall mass to equal the mass of all grains.
       t@@ -120,14 +125,24 @@ function addWallLinearFrictionless!(simulation::Simulation,
                end
            end
        
       +    # if not set, set wall surface area from the ocean grid
       +    if isnan(surface_area) && bc != "fixed"
       +        if typeof(simulation.ocean.input_file) == Bool
       +            error("simulation.ocean must be set beforehand")
       +        end
       +        surface_area = getWallSurfaceArea(simulation, normal, thickness)
       +    end
       +
            # Create wall object
            wall = WallLinearFrictionless(normal,
                                           pos,
                                           bc,
                                           mass,
                                           thickness,
       +                                   surface_area,
                                           normal_stress,
                                           vel,
       +                                   acc,
                                           force)
        
            # Add to simulation object
       t@@ -158,6 +173,18 @@ function getWallSurfaceArea(sim::Simulation, wall_index::Integer)
            end
            nothing
        end
       +function getWallSurfaceArea(sim::Simulation, normal::Vector{Float64},
       +                            thickness::Float64)
       +
       +    if normal ≈ [1., 0.]
       +        return (sim.ocean.yq[end,end] - sim.ocean.yq[1,1]) * thickness
       +    elseif normal ≈ [0., 1.]
       +        return (sim.ocean.xq[end,end] - sim.ocean.xq[1,1]) * thickness
       +    else
       +        error("Wall normal not understood")
       +    end
       +    nothing
       +end
        
        export getWallNormalStress
        """
 (DIR) diff --git a/test/wall.jl b/test/wall.jl
       t@@ -4,6 +4,7 @@
        
        info("#### $(basename(@__FILE__)) ####")
        
       +info("# Test wall initialization")
        info("Testing argument value checks")
        sim = Granular.createSimulation()
        Granular.addGrainCylindrical!(sim, [ 0., 0.], 10., 2., verbose=false)
       t@@ -16,6 +17,9 @@ Granular.addGrainCylindrical!(sim, [ 0., 0.], 10., 2., verbose=false)
        @test_throws ErrorException Granular.addWallLinearFrictionless!(sim,
                                                                        [.1, .1, .1],
                                                                        1.)
       +@test_throws ErrorException Granular.addWallLinearFrictionless!(sim,
       +                                                                [0., 1.], 1.,
       +                                                                bc="asdf")
        sim = Granular.createSimulation()
        @test_throws ErrorException Granular.addWallLinearFrictionless!(sim, [1., 0.],
                                                                        1.)
       t@@ -46,64 +50,259 @@ Granular.addWallLinearFrictionless!(sim, [0., 1.], 1., verbose=false)
        @test Granular.getWallSurfaceArea(sim, 1) ≈ 20.0*2.0
        @test Granular.getWallSurfaceArea(sim, 2) ≈ 10.0*2.0
        
       -info("Test wall-grain interaction")
       +info("# Test wall-grain interaction")
        
       -info("...wall present but no contact")
       +info("Wall present but no contact")
        sim = Granular.createSimulation()
        sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
        Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
        Granular.addWallLinearFrictionless!(sim, [1., 0.], -1.01, verbose=false)
       +Granular.setTimeStep!(sim)
        Granular.interactWalls!(sim)
        @test sim.walls[1].force ≈ 0.
        @test sim.grains[1].force[1] ≈ 0.
        @test sim.grains[1].force[2] ≈ 0.
        
       -info("...wall present but no contact")
       +info("Wall present but no contact")
        sim = Granular.createSimulation()
        sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
        Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       -Granular.addWallLinearFrictionless!(sim, [-1., 0.], +2.01, verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], +2.01, verbose=false)
       +Granular.setTimeStep!(sim)
        Granular.interactWalls!(sim)
        @test sim.walls[1].force ≈ 0.
        @test sim.grains[1].force[1] ≈ 0.
        @test sim.grains[1].force[2] ≈ 0.
        
       -info("...wall at -x")
       +info("Wall at -x")
        sim = Granular.createSimulation()
        sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
        Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
        Granular.addWallLinearFrictionless!(sim, [1., 0.], -1. + .01, verbose=false)
       +Granular.setTimeStep!(sim)
        Granular.interactWalls!(sim)
        @test sim.walls[1].force > 0.
       -@test sim.grains[1].force[1] > 0.
       +@test sim.grains[1].force[1] < 0.
        @test sim.grains[1].force[2] ≈ 0.
        
       -info("...wall at +x")
       +info("Wall at +x")
        sim = Granular.createSimulation()
        sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
        Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       -Granular.addWallLinearFrictionless!(sim, [-1., 0.], +1. - .01, verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], +1. - .01, verbose=false)
       +Granular.setTimeStep!(sim)
        Granular.interactWalls!(sim)
        @test sim.walls[1].force > 0.
        @test sim.grains[1].force[1] < 0.
        @test sim.grains[1].force[2] ≈ 0.
        
       -info("...wall at -y")
       +info("Wall at -y")
        sim = Granular.createSimulation()
        sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
        Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
        Granular.addWallLinearFrictionless!(sim, [0., 1.], -1. + .01, verbose=false)
       +Granular.setTimeStep!(sim)
        Granular.interactWalls!(sim)
       -@test sim.walls[1].force > 0.
       +@test sim.walls[1].force < 0.
        @test sim.grains[1].force[1] ≈ 0.
        @test sim.grains[1].force[2] > 0.
        
       -info("...wall at +y")
       +info("Wall at +y")
        sim = Granular.createSimulation()
        sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
        Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       -Granular.addWallLinearFrictionless!(sim, [0., -1.], +1. - .01, verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [0., 1.], +1. - .01, verbose=false)
       +Granular.setTimeStep!(sim)
        Granular.interactWalls!(sim)
        @test sim.walls[1].force > 0.
        @test sim.grains[1].force[1] ≈ 0.
        @test sim.grains[1].force[2] < 0.
       +
       +
       +info("# Testing wall dynamics")
       +
       +info("Wall present, no contact, fixed (default)")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -1.01, verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim)
       +@test sim.walls[1].force ≈ 0.
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 0.
       +@test sim.walls[1].pos ≈ -1.01
       +@test sim.grains[1].force[1] ≈ 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +
       +info("Wall present, no contact, fixed (TY2)")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -1.01, verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim, method="Two-term Taylor")
       +@test sim.walls[1].force ≈ 0.
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 0.
       +@test sim.walls[1].pos ≈ -1.01
       +@test sim.grains[1].force[1] ≈ 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +
       +info("Wall present, no contact, fixed (TY3)")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -1.01, verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +@test_throws ErrorException Granular.updateWallKinematics!(sim, method="asdf")
       +Granular.updateWallKinematics!(sim, method="Three-term Taylor")
       +@test sim.walls[1].force ≈ 0.
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 0.
       +@test sim.walls[1].pos ≈ -1.01
       +@test sim.grains[1].force[1] ≈ 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +
       +info("Wall present, contact, fixed")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -1.01, verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim)
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 0.
       +@test sim.walls[1].pos ≈ -1.01
       +
       +info("Wall present, no contact, velocity BC")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -1.01,
       +                                    bc="velocity", vel=1.0,
       +                                    verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim)
       +@test sim.walls[1].force ≈ 0.
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 1.
       +@test sim.walls[1].pos > -1.01
       +@test sim.grains[1].force[1] ≈ 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +
       +info("Wall present, no contact, velocity BC (TY2)")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -1.01,
       +                                    bc="velocity", vel=1.0,
       +                                    verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim, method="Two-term Taylor")
       +@test sim.walls[1].force ≈ 0.
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 1.
       +@test sim.walls[1].pos > -1.01
       +@test sim.grains[1].force[1] ≈ 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +
       +info("Wall present, no contact, velocity BC (TY3)")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -1.01,
       +                                    bc="velocity", vel=1.0,
       +                                    verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +@test_throws ErrorException Granular.updateWallKinematics!(sim, method="asdf")
       +Granular.updateWallKinematics!(sim, method="Three-term Taylor")
       +@test sim.walls[1].force ≈ 0.
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 1.
       +@test sim.walls[1].pos > -1.01
       +@test sim.grains[1].force[1] ≈ 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +
       +info("Wall present, contact, velocity BC (TY2)")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -0.9,
       +                                    bc="velocity", vel=1.0,
       +                                    verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim, method="Two-term Taylor")
       +@test sim.walls[1].bc == "velocity"
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 1.
       +@test sim.walls[1].pos > -0.9
       +
       +info("Wall present, contact, velocity BC (TY2)")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [10., 20., 1.0])
       +Granular.addGrainCylindrical!(sim, [ 0., 0.], 1., 2., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], -0.9,
       +                                    bc="velocity", vel=1.0,
       +                                    verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim, method="Two-term Taylor")
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 1.
       +@test sim.walls[1].pos > -0.9
       +
       +info("Wall present, contact, normal stress BC")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [2., 2., 1.])
       +Granular.addGrainCylindrical!(sim, [ 1., 1.], 1., 1., verbose=false)
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], 2.,
       +                                    bc="normal stress",
       +                                    normal_stress=0.,
       +                                    verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim)
       +@test sim.walls[1].force ≈ 0.
       +@test sim.walls[1].acc ≈ 0.
       +@test sim.walls[1].vel ≈ 0.
       +@test sim.grains[1].force[1] ≈ 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +
       +info("Wall present, contact, normal stress BC")
       +sim = Granular.createSimulation()
       +sim.ocean = Granular.createRegularOceanGrid([1, 1, 1], [2., 2., 1.])
       +Granular.addGrainCylindrical!(sim, [ 1., 1.], 1., 1., verbose=false)
       +sim.grains[1].fixed = true
       +Granular.addWallLinearFrictionless!(sim, [1., 0.], 2.,
       +                                    bc="normal stress",
       +                                    normal_stress=1e4,
       +                                    verbose=false)
       +Granular.setTimeStep!(sim)
       +Granular.interactWalls!(sim)
       +Granular.updateWallKinematics!(sim)
       +@test sim.walls[1].force ≈ 0.
       +@test sim.walls[1].acc < 0.
       +@test sim.walls[1].vel < 0.
       +@test sim.grains[1].force[1] ≈ 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +for i=1:5
       +    Granular.interactWalls!(sim)
       +    Granular.updateWallKinematics!(sim)
       +    println(sim.walls[1].pos)
       +end
       +@test sim.walls[1].force < 0.
       +@test sim.walls[1].acc < 0.
       +@test sim.walls[1].vel < 0.
       +@test sim.walls[1].pos < 1.
       +@test sim.grains[1].force[1] > 0.
       +@test sim.grains[1].force[2] ≈ 0.
       +