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:
M | src/grid.jl | | | 100 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
M | test/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