Granular.jl

Julia package for granular dynamics simulation
git clone git://src.adamsgaard.dk/Granular.jl
Log | Files | Refs | README | LICENSE

commit 3d0915f604fa11d221d503a7c9129e7419e08d33
parent 141ed18982e94bba45720f54e67d8990e9d2980b
Author: Anders Damsgaard <andersd@riseup.net>
Date:   Thu,  8 Jun 2017 13:37:00 -0400

add brute-force method for finding empty position in cell

Diffstat:
Msrc/grid.jl | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/grid.jl | 40++++++++++++++++++++++++++++++++++++++++
2 files changed, 140 insertions(+), 0 deletions(-)

diff --git a/src/grid.jl b/src/grid.jl @@ -30,6 +30,19 @@ function bilinearInterpolation(field::Array{Float64, 4}, (field[i+1, j, k, it]*x_tilde + field[i, j, k, it]*(1. - x_tilde))*(1. - y_tilde) end +function bilinearInterpolation(field::Array{Float64, 2}, + x_tilde::Float64, + y_tilde::Float64, + i::Int, + j::Int) + + if x_tilde < 0. || x_tilde > 1. || y_tilde < 0. || y_tilde > 1. + error("relative coordinates outside bounds ($(x_tilde), $(y_tilde))") + end + + return (field[i+1, j+1]*x_tilde + field[i, j+1]*(1. - x_tilde))*y_tilde + + (field[i+1, j]*x_tilde + field[i, j]*(1. - x_tilde))*(1. - y_tilde) +end """ curl(grid, x_tilde, y_tilde, i, j, k, it) @@ -363,3 +376,90 @@ function conformalQuadrilateralCoordinates(A::Array{float, 1}, end return [x_tilde, y_tilde] end + +export findEmptyPositionInGridCell +""" +Attempt locate an empty spot for an ice floe with radius `r` with center +coordinates in a specified grid cell (`i`, `j`) without overlapping any other +ice floes in that cell or the neighboring cells. This function will stop +attempting after `n_iter` iterations, each with randomly generated positions. + +This function assumes that existing ice floes have been binned according to the +grid (e.g., using `sortIceFloesInGrid()`). +""" +function findEmptyPositionInGridCell(simulation::Simulation, + grid::Any, + i::Int, + j::Int, + r::float; + n_iter::Int = 10, + seed::Int = 1, + verbose::Bool = false) + Base.Random.srand(i*j*seed) + overlap_found = false + i_iter = 0 + pos = [NaN NaN] + + nx, ny = size(grid.xh) + + for i_iter=1:n_iter + + # generate random candidate position + x_tilde = Base.Random.rand() + y_tilde = Base.Random.rand() + pos = [bilinearInterpolation(grid.xq, x_tilde, y_tilde, i, j) + bilinearInterpolation(grid.yq, x_tilde, y_tilde, i, j)] + + # search for contacts in current and eight neighboring cells + for i_neighbor_corr=[0 -1 1] + for j_neighbor_corr=[0 -1 1] + + # target cell index + it = i + i_neighbor_corr + jt = j + j_neighbor_corr + + # do not search outside grid boundaries + if it < 1 || it > nx || jt < 1 || jt > ny + continue + end + + # traverse list of ice floes in the target cell and check + # for overlaps + for icefloe_idx in grid.ice_floe_list[it, jt] + overlap = norm(simulation.ice_floes[icefloe_idx].lin_pos - + pos) - + (simulation.ice_floes[icefloe_idx].contact_radius + r) + + if overlap < 0. + overlap_found = true + break + end + end + end + if overlap_found == true + break + end + end + if overlap_found == false + break + end + end + if verbose && overlap_found == false + info("Found position $pos in cell $i,$j after $i_iter iterations") + elseif verbose && overlap_found + info("Free position not found in cell $i,$j") + end + + if overlap_found == false + if isnan(pos[1]) || isnan(pos[2]) + error("fatal error: could not determine free position in cell") + end + return pos + else + if verbose + warn("could not insert an ice floe into " * + "$(typeof(grid)) grid cell ($i, $j)") + end + return false + end +end diff --git a/test/grid.jl b/test/grid.jl @@ -193,3 +193,43 @@ atmosphere.u[2, 2, 1, 1] = 1.0 atmosphere.u[1, 2, 1, 1] = 1.0 atmosphere.v[:, :, 1, 1] = 0.0 @test SeaIce.curl(atmosphere, .5, .5, 1, 1, 1, 1) < 0. + + +info("Testing findEmptyPositionInGridCell") +sim = SeaIce.createSimulation() +sim.ocean = SeaIce.createRegularOceanGrid([4, 4, 2], [4., 4., 2.]) +SeaIce.sortIceFloesInGrid!(sim, sim.ocean, verbose=verbose) +pos = SeaIce.findEmptyPositionInGridCell(sim, sim.ocean, 1, 1, 0.5, + verbose=true) +@test pos != false +@test SeaIce.isPointInCell(sim.ocean, 1, 1, pos) == true + +sim = SeaIce.createSimulation() +sim.ocean = SeaIce.createRegularOceanGrid([4, 4, 2], [4., 4., 2.]) +SeaIce.addIceFloeCylindrical(sim, [.5, .5], 1., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [.75, .5], 1., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [.5, .75], 1., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [.75, .75], 1., 1., verbose=verbose) +SeaIce.sortIceFloesInGrid!(sim, sim.ocean, verbose=verbose) +pos = SeaIce.findEmptyPositionInGridCell(sim, sim.ocean, 1, 1, 0.5, + verbose=false) +@test pos == false + +sim = SeaIce.createSimulation() +sim.ocean = SeaIce.createRegularOceanGrid([4, 4, 2], [4., 4., 2.]) +SeaIce.sortIceFloesInGrid!(sim, sim.ocean, verbose=verbose) +pos = SeaIce.findEmptyPositionInGridCell(sim, sim.ocean, 2, 2, 0.5, + verbose=true) +@test pos != false +@test SeaIce.isPointInCell(sim.ocean, 2, 2, pos) == true + +sim = SeaIce.createSimulation() +sim.ocean = SeaIce.createRegularOceanGrid([4, 4, 2], [4., 4., 2.]) +SeaIce.addIceFloeCylindrical(sim, [1.5, 1.5], 1., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [1.75, 1.5], 1., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [1.5, 1.75], 1., 1., verbose=verbose) +SeaIce.addIceFloeCylindrical(sim, [1.75, 1.75], 1., 1., verbose=verbose) +SeaIce.sortIceFloesInGrid!(sim, sim.ocean, verbose=verbose) +pos = SeaIce.findEmptyPositionInGridCell(sim, sim.ocean, 2, 2, 0.5, + verbose=false) +@test pos == false