tadd function to set BCs and add tests of BC functionality - 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 4947424934abc67010b9a1e184b5464373f1f94a
 (DIR) parent 0c238ad9a3d7510cd2b9b285d482bf0607083dba
 (HTM) Author: Anders Damsgaard <andersd@riseup.net>
       Date:   Fri,  3 Nov 2017 14:13:40 -0400
       
       add function to set BCs and add tests of BC functionality
       
       Diffstat:
         M src/atmosphere.jl                   |       4 ++--
         M src/datatypes.jl                    |      36 +++++++++++++++++--------------
         M src/grid.jl                         |     115 +++++++++++++++++++++++++++++++
         M src/ocean.jl                        |       6 +++---
         A test/periodic-boundaries.jl         |     104 +++++++++++++++++++++++++++++++
         M test/runtests.jl                    |       1 +
       
       6 files changed, 245 insertions(+), 21 deletions(-)
       ---
 (DIR) diff --git a/src/atmosphere.jl b/src/atmosphere.jl
       t@@ -17,7 +17,7 @@ function createEmptyAtmosphere()
        
                              Array{Vector{Int}}(1, 1),
        
       -                      0, 0, 0, 0,
       +                      1, 1, 1, 1,
        
                              false)
        end
       t@@ -129,7 +129,7 @@ function createRegularAtmosphereGrid(n::Vector{Int},
                         zl,
                         u, v,
                         Array{Array{Int, 1}}(size(xh, 1), size(xh, 2)),
       -                 0, 0, 0, 0,
       +                 1, 1, 1, 1,
                         false)
        end
        
 (DIR) diff --git a/src/datatypes.jl b/src/datatypes.jl
       t@@ -166,17 +166,17 @@ h-points.  During read, the velocities are interpolated to the cell corners
        * `grain_list::Array{Float64, Int}`: indexes of grains contained in the 
            ocean grid cells.
        * `bc_west::Integer`: Boundary condition type for the west edge of the grid.
       -        0: inactive,
       -        1: periodic
       +        1: inactive,
       +        2: periodic
        * `bc_south::Integer`: Boundary condition type for the south edge of the grid.
       -        0: inactive,
       -        1: periodic
       +        1: inactive,
       +        2: periodic
        * `bc_east::Integer`: Boundary condition type for the east edge of the grid.
       -        0: inactive,
       -        1: periodic
       +        1: inactive,
       +        2: periodic
        * `bc_north::Integer`: Boundary condition type for the north edge of the grid.
       -        0: inactive,
       -        1: periodic
       +        1: inactive,
       +        2: periodic
        =#
        mutable struct Ocean
            input_file::Any
       t@@ -243,17 +243,17 @@ cell corners (q-points).
        * `grain_list::Array{Float64, Int}`: interface height relative to mean sea 
            level [m],  dimensions correspond to placement in `[xh, yh, zi, time]`.
        * `bc_west::Integer`: Boundary condition type for the west edge of the grid.
       -        0: inactive,
       -        1: periodic
       +        1: inactive,
       +        2: periodic
        * `bc_south::Integer`: Boundary condition type for the south edge of the grid.
       -        0: inactive,
       -        1: periodic
       +        1: inactive,
       +        2: periodic
        * `bc_east::Integer`: Boundary condition type for the east edge of the grid.
       -        0: inactive,
       -        1: periodic
       +        1: inactive,
       +        2: periodic
        * `bc_north::Integer`: Boundary condition type for the north edge of the grid.
       -        0: inactive,
       -        1: periodic
       +        1: inactive,
       +        2: periodic
        =#
        mutable struct Atmosphere
            input_file::Any
       t@@ -306,3 +306,7 @@ mutable struct Simulation
        
            Nc_max::Int
        end
       +
       +# Mappings between boundary condition keys (Integers) and strings
       +const grid_bc_strings = ["inactive", "periodic"]
       +const grid_bc_flags = Dict(zip(grid_bc_strings, 1:length(grid_bc_strings)))
 (DIR) diff --git a/src/grid.jl b/src/grid.jl
       t@@ -617,3 +617,118 @@ function copyGridSortingInfo!(ocean::Ocean, atmosphere::Atmosphere,
            atmosphere.grain_list = deepcopy(ocean.grain_list)
            nothing
        end
       +
       +export setGridBoundaryConditions!
       +"""
       +    setGridBoundaryConditions!(grid, grid_face, mode)
       +
       +Set boundary conditions for the granular phase at the edges of `Ocean` or
       +`Atmosphere` grids.  The target boundary can be selected through the `grid_face`
       +argument, or the same boundary condition can be applied to all grid boundaries
       +at once.
       +
       +When the center coordinate of grains crosses an inactive boundary (`mode =
       +"inactive"`), the grain is disabled (`GrainCylindrical.enabled = false`).  This
       +keeps the grain in memory, but stops it from moving or interacting with other
       +grains.  *By default, all boundaries are inactive*.
       +
       +If the center coordinate of a grain crosses a periodic boundary (`mode =
       +periodic`), the grain is repositioned to the opposite side of the model domain.
       +Grains can interact mechanically across the periodic boundary.
       +
       +# Arguments
       +* `grid::Any`: `Ocean` or `Atmosphere` grid to apply the boundary condition to.
       +* `grid_face::String`: Grid face to apply the boundary condition to.  Valid
       +    values are any combination and sequence of `"west"` (-x), `"south"` (-y),
       +    `"east"` (+x), `"north"` (+y).  The values may be delimited in any way.
       +    Also, and by default, all boundaries can be selected with `"all"` (-x, -y,
       +    +x, +y), which overrides any other face selection.
       +* `mode::String`: Boundary behavior, accepted values are `"inactive"` and
       +    `"periodic"`.  You cannot specify more than one mode at a time, so if
       +    several modes are desired as boundary conditions for the grid, several calls
       +    to this function should be made.
       +* `verbose::Bool`: Confirm boundary conditions by reporting values to console.
       +
       +# Examples
       +Set all boundaries for the ocean grid to be periodic:
       +
       +    setGridBoundaryConditions!(ocean, "periodic", "all")
       +
       +Set the south-north boundaries to be inactive, but the west-east boundaries to
       +be periodic:
       +
       +    setGridBoundaryConditions!(ocean, "inactive", "south north")
       +    setGridBoundaryConditions!(ocean, "periodic", "west east")
       +
       +"""
       +function setGridBoundaryConditions!(grid::Any,
       +                                    mode::String,
       +                                    grid_face::String = "all";
       +                                    verbose::Bool=true)
       +
       +    something_changed = false
       +
       +    if length(mode) <= 1
       +        error("The mode string is required ('$mode')")
       +    end
       +
       +    if !(mode in grid_bc_strings)
       +        error("Mode '$mode' not recognized as a valid boundary condition type")
       +    end
       +
       +    if contains(grid_face, "west")
       +        grid.bc_west = grid_bc_flags[mode]
       +        something_changed = true
       +    end
       +
       +    if contains(grid_face, "south")
       +        grid.bc_south = grid_bc_flags[mode]
       +        something_changed = true
       +    end
       +
       +    if contains(grid_face, "east")
       +        grid.bc_east = grid_bc_flags[mode]
       +        something_changed = true
       +    end
       +
       +    if contains(grid_face, "north")
       +        grid.bc_north = grid_bc_flags[mode]
       +        something_changed = true
       +    end
       +
       +    if grid_face == "all"
       +        grid.bc_west  = grid_bc_flags[mode]
       +        grid.bc_south = grid_bc_flags[mode]
       +        grid.bc_east  = grid_bc_flags[mode]
       +        grid.bc_north = grid_bc_flags[mode]
       +        something_changed = true
       +    end
       +
       +    if !something_changed
       +        error("grid_face string '$grid_face' not understood, must be east, " *
       +              "west, north, and/or south.")
       +    end
       +
       +    if verbose
       +        reportGridBoundaryConditions(grid)
       +    end
       +    nothing
       +end
       +
       +export reportGridBoundaryConditions
       +"""
       +    reportGridBoundaryConditions(grid)
       +
       +Report the boundary conditions for the grid to the console.
       +"""
       +function reportGridBoundaryConditions(grid::Any)
       +    println("West  (-x): " * grid_bc_strings[grid.bc_west] * 
       +            "\t($(grid.bc_west))")
       +    println("East  (+x): " * grid_bc_strings[grid.bc_east] * 
       +            "\t($(grid.bc_east))")
       +    println("South (-y): " * grid_bc_strings[grid.bc_south] * 
       +            "\t($(grid.bc_south))")
       +    println("North (+y): " * grid_bc_strings[grid.bc_north] * 
       +            "\t($(grid.bc_north))")
       +    nothing
       +end
 (DIR) diff --git a/src/ocean.jl b/src/ocean.jl
       t@@ -18,7 +18,7 @@ function createEmptyOcean()
                         zeros(1,1,1,1),
                         zeros(1,1,1,1),
                         Array{Array{Int, 1}}(1, 1),
       -                 0, 0, 0, 0)
       +                 1, 1, 1, 1)
        end
        
        export readOceanNetCDF
       t@@ -61,7 +61,7 @@ function readOceanNetCDF(velocity_file::String, grid_file::String)
                          h,
                          e,
                          Array{Array{Int, 1}}(size(xh, 1), size(xh, 2)),
       -                  0, 0, 0, 0
       +                  1, 1, 1, 1
                         )
            return ocean
        end
       t@@ -242,7 +242,7 @@ function createRegularOceanGrid(n::Array{Int, 1},
                         zl, zi,
                         u, v, h, e,
                         Array{Array{Int, 1}}(size(xh, 1), size(xh, 2)),
       -                 0, 0, 0, 0)
       +                 1, 1, 1, 1)
        end
        
        export addOceanDrag!
 (DIR) diff --git a/test/periodic-boundaries.jl b/test/periodic-boundaries.jl
       t@@ -0,0 +1,104 @@
       +#!/usr/bin/env julia
       +
       +info("#### $(basename(@__FILE__)) ####")
       +
       +verbose=false
       +i = 0
       +
       +info("Testing assignment and reporting of grid boundary conditions")
       +ocean = Granular.createEmptyOcean()
       +
       +Test.@test ocean.bc_west == 1
       +Test.@test ocean.bc_east == 1
       +Test.@test ocean.bc_north == 1
       +Test.@test ocean.bc_south == 1
       +
       +const originalSTDOUT = STDOUT
       +(out_r, out_w) = redirect_stdout()
       +Granular.reportGridBoundaryConditions(ocean)
       +close(out_w)
       +redirect_stdout(originalSTDOUT)
       +output = convert(String, readavailable(out_r))
       +Test.@test output == """West  (-x): inactive\t(1)
       +East  (+x): inactive\t(1)
       +South (-y): inactive\t(1)
       +North (+y): inactive\t(1)
       +"""
       +
       +(out_r, out_w) = redirect_stdout()
       +Granular.setGridBoundaryConditions!(ocean, "periodic", "south, west", verbose=true)
       +close(out_w)
       +redirect_stdout(originalSTDOUT)
       +output = convert(String, readavailable(out_r))
       +Test.@test output == """West  (-x): periodic\t(2)
       +East  (+x): inactive\t(1)
       +South (-y): periodic\t(2)
       +North (+y): inactive\t(1)
       +"""
       +Test.@test ocean.bc_west == 2
       +Test.@test ocean.bc_east == 1
       +Test.@test ocean.bc_north == 1
       +Test.@test ocean.bc_south == 2
       +
       +(out_r, out_w) = redirect_stdout()
       +Granular.setGridBoundaryConditions!(ocean, "inactive", "all", verbose=false)
       +close(out_w)
       +redirect_stdout(originalSTDOUT)
       +output = convert(String, readavailable(out_r))
       +Test.@test output == ""
       +Test.@test ocean.bc_west == 1
       +Test.@test ocean.bc_east == 1
       +Test.@test ocean.bc_north == 1
       +Test.@test ocean.bc_south == 1
       +
       +(out_r, out_w) = redirect_stdout()
       +Granular.setGridBoundaryConditions!(ocean, "periodic", "all")
       +close(out_w)
       +output = convert(String, readavailable(out_r))
       +redirect_stdout(originalSTDOUT)
       +Test.@test output == """West  (-x): periodic\t(2)
       +East  (+x): periodic\t(2)
       +South (-y): periodic\t(2)
       +North (+y): periodic\t(2)
       +"""
       +Test.@test ocean.bc_west == 2
       +Test.@test ocean.bc_east == 2
       +Test.@test ocean.bc_north == 2
       +Test.@test ocean.bc_south == 2
       +
       +(out_r, out_w) = redirect_stdout()
       +Granular.setGridBoundaryConditions!(ocean, "inactive")
       +close(out_w)
       +output = convert(String, readavailable(out_r))
       +redirect_stdout(originalSTDOUT)
       +Test.@test output == """West  (-x): inactive\t(1)
       +East  (+x): inactive\t(1)
       +South (-y): inactive\t(1)
       +North (+y): inactive\t(1)
       +"""
       +Test.@test ocean.bc_west == 1
       +Test.@test ocean.bc_east == 1
       +Test.@test ocean.bc_north == 1
       +Test.@test ocean.bc_south == 1
       +
       +(out_r, out_w) = redirect_stdout()
       +Granular.setGridBoundaryConditions!(ocean, "periodic")
       +close(out_w)
       +output = convert(String, readavailable(out_r))
       +redirect_stdout(originalSTDOUT)
       +Test.@test output == """West  (-x): periodic\t(2)
       +East  (+x): periodic\t(2)
       +South (-y): periodic\t(2)
       +North (+y): periodic\t(2)
       +"""
       +Test.@test ocean.bc_west == 2
       +Test.@test ocean.bc_east == 2
       +Test.@test ocean.bc_north == 2
       +Test.@test ocean.bc_south == 2
       +
       +Test.@test_throws ErrorException Granular.setGridBoundaryConditions!(ocean,
       +                                                                     "periodic",
       +                                                                     "asdf")
       +
       +Test.@test_throws ErrorException Granular.setGridBoundaryConditions!(ocean,
       +                                                                     "asdf")
 (DIR) diff --git a/test/runtests.jl b/test/runtests.jl
       t@@ -13,6 +13,7 @@ include("netcdf.jl")
        include("vtk.jl")
        include("jld.jl")
        include("grid.jl")
       +include("periodic-boundaries.jl")
        include("ocean.jl")
        include("atmosphere.jl")
        include("memory-management.jl")