commit a86d2ec05f76ac24aabe853af5b7da9296365c23
parent f8aa00babd9ab63c2f2454e05f18043c6f62a1d8
Author: Anders Damsgaard <andersd@riseup.net>
Date: Sat, 3 Jun 2017 10:08:38 -0400
add atmosphere tests, fix many grid-related issues
Diffstat:
8 files changed, 204 insertions(+), 33 deletions(-)
diff --git a/src/atmosphere.jl b/src/atmosphere.jl
@@ -114,19 +114,16 @@ function createRegularAtmosphereGrid(n::Array{Int, 1},
yh = repmat(linspace(origo[2] + .5*dx[2], L[2] - .5*dx[2], n[2])', n[1], 1)
zl = -linspace(.5*dx[3], L[3] - .5*dx[3], n[3])
- zi = -linspace(0., L[3], n[3] + 1)
u = zeros(n[1] + 1, n[2] + 1, n[3], length(time))
v = zeros(n[1] + 1, n[2] + 1, n[3], length(time))
- h = zeros(n[1] + 1, n[2] + 1, n[3], length(time))
- e = zeros(n[1] + 1, n[2] + 1, n[3], length(time))
return Atmosphere(name,
time,
xq, yq,
xh, yh,
- zl, zi,
- u, v, h, e,
+ zl,
+ u, v,
Array{Array{Int, 1}}(size(xh, 1), size(xh, 2)))
end
@@ -140,8 +137,7 @@ function addAtmosphereDrag!(simulation::Simulation)
error("no atmosphere data read")
end
- u, v, h, e = interpolateAtmosphereState(simulation.atmosphere,
- simulation.time)
+ u, v = interpolateAtmosphereState(simulation.atmosphere, simulation.time)
for ice_floe in simulation.ice_floes
@@ -203,7 +199,7 @@ function applyAtmosphereVorticityToIceFloe!(ice_floe::IceFloeCylindrical,
rho_a = 1.2754 # atmosphere density
ice_floe.torque +=
- pi*ice_floe.areal_radius^4.*rho_o*
+ pi*ice_floe.areal_radius^4.*rho_a*
(ice_floe.areal_radius/5.*ice_floe.atmosphere_drag_coeff_horiz +
freeboard*ice_floe.atmosphere_drag_coeff_vert)*
abs(.5*atmosphere_curl - ice_floe.ang_vel)*
diff --git a/src/contact_search.jl b/src/contact_search.jl
@@ -24,10 +24,10 @@ function findContacts!(simulation::Simulation;
findContactsAllToAll!(simulation)
elseif method == "ocean grid"
- findContactsOceanGrid!(simulation)
+ findContactsInGrid!(simulation, simulation.ocean)
elseif method == "atmosphere grid"
- error("not yet implemented")
+ findContactsInGrid!(simulation, simulation.atmosphere)
else
error("Unknown contact search method '$method'")
@@ -79,19 +79,25 @@ function findContactsAllToAll!(simulation::Simulation)
end
end
-export findContactsOceanGrid!
+export findContactsInGrid!
"""
- findContactsOceanGrid!(simulation)
+ findContactsInGrid!(simulation)
Perform an O(n*log(n)) cell-based contact search between all ice floes in the
-`simulation` object. Contacts between fixed ice floes are ignored.
+`simulation` object. Contacts between fixed or disabled ice floes are ignored.
"""
-function findContactsOceanGrid!(simulation::Simulation)
+function findContactsInGrid!(simulation::Simulation, grid::Any)
for idx_i = 1:length(simulation.ice_floes)
- grid_pos = simulation.ice_floes[idx_i].ocean_grid_pos
- nx, ny = size(simulation.ocean.xh)
+ if typeof(grid) == Ocean
+ grid_pos = simulation.ice_floes[idx_i].ocean_grid_pos
+ elseif typeof(grid) == Atmosphere
+ grid_pos = simulation.ice_floes[idx_i].atmosphere_grid_pos
+ else
+ error("grid type not understood")
+ end
+ nx, ny = size(grid.xh)
for i=(grid_pos[1] - 1):(grid_pos[1] + 1)
for j=(grid_pos[2] - 1):(grid_pos[2] + 1)
@@ -101,7 +107,7 @@ function findContactsOceanGrid!(simulation::Simulation)
continue
end
- for idx_j in simulation.ocean.ice_floe_list[i, j]
+ for idx_j in grid.ice_floe_list[i, j]
checkAndAddContact!(simulation, idx_i, idx_j)
end
end
@@ -109,7 +115,7 @@ function findContactsOceanGrid!(simulation::Simulation)
end
end
-export addContact!
+export checkAndAddContact!
"""
checkAndAddContact!(simulation, i, j)
diff --git a/src/grid.jl b/src/grid.jl
@@ -158,26 +158,26 @@ end
export findCellContainingPoint
"""
- findCellContainingPoint(ocean, point[, method])
+ findCellContainingPoint(grid, point[, method])
-Returns the `i`, `j` index of the ocean grid cell containing the `point`.
+Returns the `i`, `j` index of the grid cell containing the `point`.
The function uses either an area-based approach (`method = "Area"`), or a
conformal mapping approach (`method = "Conformal"`). The area-based approach is
more robust. This function returns the coordinates of the cell. If no match is
found the function returns `(0,0)`.
# Arguments
-* `ocean::Ocean`: object containing ocean data.
+* `grid::Any`: grid object containing ocean or atmosphere data.
* `point::Array{float, 1}`: two-dimensional vector of point to check.
* `method::String`: approach to use for determining if point is inside cell or
not, can be "Conformal" (default) or "Areal".
"""
-function findCellContainingPoint(ocean::Ocean, point::Array{float, 1};
+function findCellContainingPoint(grid::Any, point::Array{float, 1};
method::String="Conformal")
- for i=1:size(ocean.xh, 1)
- for j=1:size(ocean.yh, 2)
- if isPointInCell(ocean, i, j, point, method=method)
+ for i=1:size(grid.xh, 1)
+ for j=1:size(grid.yh, 2)
+ if isPointInCell(grid, i, j, point, method=method)
return i, j
end
end
@@ -188,22 +188,22 @@ end
export getNonDimensionalCellCoordinates
"""
Returns the non-dimensional conformal mapped coordinates for point `point` in
-cell `i,j`, based off the coordinates in the `ocean` grid.
+cell `i,j`, based off the coordinates in the grid.
This function is a wrapper for `getCellCornerCoordinates()` and
`conformalQuadrilateralCoordinates()`.
"""
-function getNonDimensionalCellCoordinates(ocean::Ocean, i::Int, j::Int,
+function getNonDimensionalCellCoordinates(grid::Any, i::Int, j::Int,
point::Array{float, 1})
- sw, se, ne, nw = getCellCornerCoordinates(ocean, i, j)
+ sw, se, ne, nw = getCellCornerCoordinates(grid, i, j)
x_tilde, y_tilde = conformalQuadrilateralCoordinates(sw, se, ne, nw, point)
return [x_tilde, y_tilde]
end
export isPointInCell
"""
-Check if a 2d point is contained inside a cell from the ocean grid.
+Check if a 2d point is contained inside a cell from the supplied grid.
The function uses either an area-based approach (`method = "Area"`), or a
conformal mapping approach (`method = "Conformal"`). The area-based approach is
more robust. This function returns `true` or `false`.
diff --git a/src/simulation.jl b/src/simulation.jl
@@ -111,7 +111,7 @@ function run!(simulation::Simulation;
zeroForcesAndTorques!(simulation)
if typeof(simulation.atmosphere.input_file) != Bool
- sortIceFloesInGrid!(sim, sim.atmosphere)
+ sortIceFloesInGrid!(simulation, simulation.atmosphere)
end
if typeof(simulation.ocean.input_file) != Bool
diff --git a/test/atmosphere.jl b/test/atmosphere.jl
@@ -0,0 +1,127 @@
+#!/usr/bin/env julia
+
+# Check if atmosphere-specific functions and grid operations are functioning
+# correctly
+
+info("#### $(basename(@__FILE__)) ####")
+
+info("Testing regular grid generation")
+sim = SeaIce.createSimulation()
+sim.atmosphere = SeaIce.createRegularAtmosphereGrid([6, 6, 6], [1., 1., 1.])
+@test size(sim.atmosphere.xq) == (7, 7)
+@test size(sim.atmosphere.yq) == (7, 7)
+@test size(sim.atmosphere.xh) == (6, 6)
+@test size(sim.atmosphere.yh) == (6, 6)
+@test sim.atmosphere.xq[1, :, 1] ≈ zeros(7)
+@test sim.atmosphere.xq[4, :, 1] ≈ .5*ones(7)
+@test sim.atmosphere.xq[end, :, 1] ≈ 1.*ones(7)
+@test sim.atmosphere.yq[:, 1, 1] ≈ zeros(7)
+@test sim.atmosphere.yq[:, 4, 1] ≈ .5*ones(7)
+@test sim.atmosphere.yq[:, end, 1] ≈ 1.*ones(7)
+@test size(sim.atmosphere.u) == (7, 7, 6, 1)
+@test size(sim.atmosphere.v) == (7, 7, 6, 1)
+@test sim.atmosphere.u ≈ zeros(7, 7, 6, 1)
+@test sim.atmosphere.v ≈ zeros(7, 7, 6, 1)
+
+info("Testing velocity drag interaction (static atmosphere)")
+SeaIce.addIceFloeCylindrical(sim, [.5, .5], .25, .1)
+SeaIce.setTotalTime!(sim, 5.)
+SeaIce.setTimeStep!(sim)
+sim_init = deepcopy(sim)
+sim.ice_floes[1].lin_vel[1] = 0.1
+E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+SeaIce.run!(sim, verbose=false)
+E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+@test E_kin_rot_init ≈ E_kin_rot_final # no rotation before or after
+@test E_kin_lin_init > E_kin_lin_final # linear velocity lost due to atmos drag
+
+info("Testing velocity drag interaction (static ice floe)")
+sim = deepcopy(sim_init)
+sim.atmosphere.v[:, :, 1, 1] = 0.1
+E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+SeaIce.run!(sim, verbose=false)
+E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+@test E_kin_rot_init ≈ E_kin_rot_final # no rotation before or after
+@test E_kin_lin_init < E_kin_lin_final # linear vel. gained due to atmos drag
+
+info("Testing vortex interaction (static atmosphere)")
+sim = deepcopy(sim_init)
+sim.ice_floes[1].ang_vel = 0.1
+E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+SeaIce.run!(sim, verbose=false)
+E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+@test E_kin_rot_init > E_kin_rot_final # energy lost to atmosphere
+@test sim.ice_floes[1].ang_vel > 0. # check angular velocity orientation
+@test sim.ice_floes[1].ang_pos > 0. # check angular position orientation
+@test E_kin_lin_init ≈ E_kin_lin_final # no linear velocity gained
+
+info("Testing vortex interaction (static ice floe)")
+sim = deepcopy(sim_init)
+sim.atmosphere = SeaIce.createRegularAtmosphereGrid([1, 1, 1], [1., 1., 1.])
+sim.ice_floes[1].lin_pos[1] = 0.5
+sim.ice_floes[1].lin_pos[2] = 0.5
+sim.atmosphere.v[1, :, 1, 1] = -0.1
+sim.atmosphere.v[2, :, 1, 1] = 0.1
+E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+SeaIce.run!(sim, verbose=false)
+E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+@test sim.ice_floes[1].ang_vel > 0. # check angular velocity orientation
+@test sim.ice_floes[1].ang_pos > 0. # check angular position orientation
+@test E_kin_rot_init < E_kin_rot_final # rotation after due to atm vortex
+@test E_kin_lin_init ≈ E_kin_lin_final # no linear velocity gained
+
+sim = deepcopy(sim_init)
+sim.atmosphere = SeaIce.createRegularAtmosphereGrid([1, 1, 1], [1., 1., 1.])
+sim.ice_floes[1].lin_pos[1] = 0.5
+sim.ice_floes[1].lin_pos[2] = 0.5
+sim.atmosphere.v[1, :, 1, 1] = 0.1
+sim.atmosphere.v[2, :, 1, 1] = -0.1
+E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+SeaIce.run!(sim, verbose=false)
+E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+@test sim.ice_floes[1].ang_vel < 0. # check angular velocity orientation
+@test sim.ice_floes[1].ang_pos < 0. # check angular position orientation
+@test E_kin_rot_init < E_kin_rot_final # rotation after due to atm vortex
+@test E_kin_lin_init ≈ E_kin_lin_final # no linear velocity gained
+
+sim = deepcopy(sim_init)
+sim.atmosphere = SeaIce.createRegularAtmosphereGrid([1, 1, 1], [1., 1., 1.])
+sim.ice_floes[1].lin_pos[1] = 0.5
+sim.ice_floes[1].lin_pos[2] = 0.5
+sim.atmosphere.u[:, 1, 1, 1] = -0.1
+sim.atmosphere.u[:, 2, 1, 1] = 0.1
+E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+SeaIce.run!(sim, verbose=false)
+E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+@test sim.ice_floes[1].ang_vel < 0. # check angular velocity orientation
+@test sim.ice_floes[1].ang_pos < 0. # check angular position orientation
+@test E_kin_rot_init < E_kin_rot_final # rotation after due to atm vortex
+@test E_kin_lin_init ≈ E_kin_lin_final # no linear velocity gained
+
+sim = deepcopy(sim_init)
+sim.atmosphere = SeaIce.createRegularAtmosphereGrid([1, 1, 1], [1., 1., 1.])
+sim.ice_floes[1].lin_pos[1] = 0.5
+sim.ice_floes[1].lin_pos[2] = 0.5
+sim.atmosphere.u[:, 1, 1, 1] = 0.1
+sim.atmosphere.u[:, 2, 1, 1] = -0.1
+E_kin_lin_init = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_init = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+SeaIce.run!(sim, verbose=false)
+E_kin_lin_final = SeaIce.totalIceFloeKineticTranslationalEnergy(sim)
+E_kin_rot_final = SeaIce.totalIceFloeKineticRotationalEnergy(sim)
+@test sim.ice_floes[1].ang_vel > 0. # check angular velocity orientation
+@test sim.ice_floes[1].ang_pos > 0. # check angular position orientation
+@test E_kin_rot_init < E_kin_rot_final # rotation after due to atm vortex
+@test E_kin_lin_init ≈ E_kin_lin_final # no linear velocity gained
diff --git a/test/contact-search-and-geometry.jl b/test/contact-search-and-geometry.jl
@@ -126,7 +126,7 @@ info("Testing findContactsGrid(...)")
sim = deepcopy(sim_copy)
sim.ocean = SeaIce.createRegularOceanGrid([4, 4, 2], [80., 80., 2.])
SeaIce.sortIceFloesInGrid!(sim, sim.ocean)
-SeaIce.findContactsOceanGrid!(sim)
+SeaIce.findContactsInGrid!(sim, sim.ocean)
@test 2 == sim.ice_floes[1].contacts[1]
for ic=2:32
@@ -145,7 +145,7 @@ sim = deepcopy(sim_copy)
sim.ocean = SeaIce.createRegularOceanGrid([4, 4, 2], [80., 80., 2.])
sim.ice_floes[1].fixed = true
SeaIce.sortIceFloesInGrid!(sim, sim.ocean)
-SeaIce.findContactsOceanGrid!(sim)
+SeaIce.findContactsInGrid!(sim, sim.ocean)
@test 2 == sim.ice_floes[1].contacts[1]
for ic=2:32
@@ -165,7 +165,7 @@ sim.ocean = SeaIce.createRegularOceanGrid([4, 4, 2], [80., 80., 2.])
sim.ice_floes[1].fixed = true
sim.ice_floes[2].fixed = true
SeaIce.sortIceFloesInGrid!(sim, sim.ocean)
-SeaIce.findContactsOceanGrid!(sim)
+SeaIce.findContactsInGrid!(sim, sim.ocean)
for ic=1:32
@test 0 == sim.ice_floes[1].contacts[ic]
diff --git a/test/grid.jl b/test/grid.jl
@@ -152,3 +152,44 @@ ocean.u[2, 2, 1, 1] = 1.0
ocean.u[1, 2, 1, 1] = 1.0
ocean.v[:, :, 1, 1] = 0.0
@test SeaIce.curl(ocean, .5, .5, 1, 1, 1, 1) < 0.
+
+info("Testing atmosphere drag")
+sim = SeaIce.createSimulation()
+sim.atmosphere = SeaIce.createRegularAtmosphereGrid([4, 4, 2], [4., 4., 2.])
+atmosphere = SeaIce.createRegularAtmosphereGrid([4, 4, 2], [4., 4., 2.])
+sim.atmosphere.u[:,:,1,1] = 5.
+SeaIce.addIceFloeCylindrical(sim, [2.5, 3.5], 1., 1., verbose=verbose)
+SeaIce.addIceFloeCylindrical(sim, [2.6, 2.5], 1., 1., verbose=verbose)
+SeaIce.sortIceFloesInGrid!(sim, sim.atmosphere, verbose=verbose)
+sim.time = ocean.time[1]
+SeaIce.addAtmosphereDrag!(sim)
+@test sim.ice_floes[1].force[1] > 0.
+@test sim.ice_floes[1].force[2] ≈ 0.
+@test sim.ice_floes[2].force[1] > 0.
+@test sim.ice_floes[2].force[2] ≈ 0.
+sim.atmosphere.u[:,:,1,1] = -5.
+sim.atmosphere.v[:,:,1,1] = 5.
+SeaIce.addIceFloeCylindrical(sim, [2.5, 3.5], 1., 1., verbose=verbose)
+SeaIce.addIceFloeCylindrical(sim, [2.6, 2.5], 1., 1., verbose=verbose)
+SeaIce.sortIceFloesInGrid!(sim, sim.atmosphere, verbose=verbose)
+sim.time = ocean.time[1]
+SeaIce.addAtmosphereDrag!(sim)
+@test sim.ice_floes[1].force[1] < 0.
+@test sim.ice_floes[1].force[2] > 0.
+@test sim.ice_floes[2].force[1] < 0.
+@test sim.ice_floes[2].force[2] > 0.
+
+info("Testing curl function")
+atmosphere.u[1, 1, 1, 1] = 1.0
+atmosphere.u[2, 1, 1, 1] = 1.0
+atmosphere.u[2, 2, 1, 1] = 0.0
+atmosphere.u[1, 2, 1, 1] = 0.0
+atmosphere.v[:, :, 1, 1] = 0.0
+@test SeaIce.curl(atmosphere, .5, .5, 1, 1, 1, 1) > 0.
+
+atmosphere.u[1, 1, 1, 1] = 0.0
+atmosphere.u[2, 1, 1, 1] = 0.0
+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.
diff --git a/test/runtests.jl b/test/runtests.jl
@@ -12,3 +12,4 @@ include("netcdf.jl")
include("vtk.jl")
include("grid.jl")
include("ocean.jl")
+include("atmosphere.jl")