tadd atmosphere tests, fix many grid-related issues - Granular.jl - Julia packa… | |
git clone git://src.adamsgaard.dk/Granular.jl | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit a86d2ec05f76ac24aabe853af5b7da9296365c23 | |
parent f8aa00babd9ab63c2f2454e05f18043c6f62a1d8 | |
Author: Anders Damsgaard <[email protected]> | |
Date: Sat, 3 Jun 2017 10:08:38 -0400 | |
add atmosphere tests, fix many grid-related issues | |
Diffstat: | |
M src/atmosphere.jl | 12 ++++-------- | |
M src/contact_search.jl | 26 ++++++++++++++++---------- | |
M src/grid.jl | 22 +++++++++++----------- | |
M src/simulation.jl | 2 +- | |
A test/atmosphere.jl | 127 +++++++++++++++++++++++++++++… | |
M test/contact-search-and-geometry.jl | 6 +++--- | |
M test/grid.jl | 41 +++++++++++++++++++++++++++++… | |
M test/runtests.jl | 1 + | |
8 files changed, 204 insertions(+), 33 deletions(-) | |
--- | |
diff --git a/src/atmosphere.jl b/src/atmosphere.jl | |
t@@ -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 | |
t@@ -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 | |
t@@ -203,7 +199,7 @@ function applyAtmosphereVorticityToIceFloe!(ice_floe::IceF… | |
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 | |
t@@ -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'") | |
t@@ -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) | |
t@@ -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 | |
t@@ -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 | |
t@@ -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 … | |
more robust. This function returns the coordinates of the cell. If no match … | |
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 | |
t@@ -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 … | |
more robust. This function returns `true` or `false`. | |
diff --git a/src/simulation.jl b/src/simulation.jl | |
t@@ -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 | |
t@@ -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 dr… | |
+ | |
+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-geom… | |
t@@ -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 | |
t@@ -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 | |
t@@ -165,7 +165,7 @@ sim.ocean = SeaIce.createRegularOceanGrid([4, 4, 2], [80.,… | |
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 | |
t@@ -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 | |
t@@ -12,3 +12,4 @@ include("netcdf.jl") | |
include("vtk.jl") | |
include("grid.jl") | |
include("ocean.jl") | |
+include("atmosphere.jl") |