tadd angular drag from ocean vorticity - 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 e6423e746bc3d5ee39a065427f18b4be7a8021b3
 (DIR) parent 6682dda64ebfab3793c6d916f258f5925892df6f
 (HTM) Author: Anders Damsgaard <andersd@riseup.net>
       Date:   Thu, 11 May 2017 16:45:39 -0400
       
       add angular drag from ocean vorticity
       
       Diffstat:
         M src/grid.jl                         |      39 ++++++++++++++++++++++++++++++-
         M src/ocean.jl                        |      27 +++++++++++++++++++++++++--
         M test/grid.jl                        |      15 +++++++++++++++
         M test/ocean.jl                       |     142 ++++++++++++++++++++++++++-----
       
       4 files changed, 201 insertions(+), 22 deletions(-)
       ---
 (DIR) diff --git a/src/grid.jl b/src/grid.jl
       t@@ -7,7 +7,8 @@ south-west (-x, -y)-facing corner.
        
        # Arguments
        * `field::Array{Float64, 4}`: a scalar field to interpolate from
       -* `p::float`: point position
       +* `x_tilde::float`: x point position [0;1]
       +* `y_tilde::float`: y point position [0;1]
        * `i::Int`: i-index of cell containing point
        * `j::Int`: j-index of scalar field to interpolate from
        * `it::Int`: time step from scalar field to interpolate from
       t@@ -30,6 +31,42 @@ function bilinearInterpolation(field::Array{Float64, 4},
                    field[i, j, k, it]*(1. - x_tilde))*(1. - y_tilde)
        end
        
       +"""
       +    curl(ocean, x_tilde, y_tilde, i, j, k, it)
       +
       +Use bilinear interpolation to interpolate curl value for a staggered velocity 
       +grid to an arbitrary position in a cell.  Assumes south-west convention, i.e.  
       +(i,j) is located at the south-west (-x, -y)-facing corner.
       +
       +# Arguments
       +* `ocean::Ocean`: grid for which to determine curl
       +* `x_tilde::float`: x point position [0;1]
       +* `y_tilde::float`: y point position [0;1]
       +* `i::Int`: i-index of cell containing point
       +* `j::Int`: j-index of scalar field to interpolate from
       +* `it::Int`: time step from scalar field to interpolate from
       +"""
       +function curl(ocean::Ocean,
       +              x_tilde::Float64,
       +              y_tilde::Float64,
       +              i::Int,
       +              j::Int,
       +              k::Int,
       +              it::Int)
       +
       +    sw, se, ne, nw = getCellCornerCoordinates(ocean, i, j)
       +    sw_se = norm(sw - se)
       +    se_ne = norm(se - ne)
       +    nw_ne = norm(nw - ne)
       +    sw_nw = norm(sw - nw)
       +
       +    return (
       +    ((ocean.v[i+1, j  , k,it] - ocean.v[i  , j  , k,it])/sw_se*(1. - y_tilde) +
       +     ((ocean.v[i+1, j+1, k,it] - ocean.v[i  , j+1, k,it])/nw_ne)*y_tilde) -
       +    ((ocean.u[i  , j+1, k,it] - ocean.u[i  , j  , k,it])/sw_nw*(1. - x_tilde) +
       +     ((ocean.u[i+1, j+1, k,it] - ocean.u[i+1, j  , k,it])/se_ne)*x_tilde))
       +end
       +
        export sortIceFloesInOceanGrid!
        """
        Find ice-floe positions in ocean grid, based on their center positions.
 (DIR) diff --git a/src/ocean.jl b/src/ocean.jl
       t@@ -245,7 +245,8 @@ end
        
        export addOceanDrag!
        """
       -Add Stokes-type drag from velocity difference between ocean and all ice floes.
       +Add drag from linear and angular velocity difference between ocean and all ice 
       +floes.
        """
        function addOceanDrag!(simulation::Simulation)
            if typeof(simulation.ocean.input_file) == Bool
       t@@ -276,8 +277,10 @@ function addOceanDrag!(simulation::Simulation)
        
                u_local = bilinearInterpolation(u, x_tilde, y_tilde, i, j, k, 1)
                v_local = bilinearInterpolation(v, x_tilde, y_tilde, i, j, k, 1)
       +        vel_curl = curl(simulation.ocean, x_tilde, y_tilde, i, j, k, 1)
        
                applyOceanDragToIceFloe!(ice_floe, u_local, v_local)
       +        applyOceanVorticityToIceFloe!(ice_floe, vel_curl)
            end
        end
        
       t@@ -297,6 +300,26 @@ function applyOceanDragToIceFloe!(ice_floe::IceFloeCylindrical,
            width = ice_floe.areal_radius*2.
        
            ice_floe.force +=
       -        rho_o * (.5*c_o_v*width*draft*freeboard + c_o_h*length*width) *
       +        rho_o * (.5*c_o_v*width*draft + c_o_h*length*width) *
                ([u, v] - ice_floe.lin_vel)*norm([u, v] - ice_floe.lin_vel)
        end
       +
       +export applyOceanVorticityToIceFloe!
       +"""
       +Add Stokes-type torque from angular velocity difference between ocean and a 
       +single ice floe.  See Eq. 9.28 in "Introduction to Fluid Mechanics" by Nakayama 
       +and Boucher, 1999.
       +"""
       +function applyOceanVorticityToIceFloe!(ice_floe::IceFloeCylindrical, 
       +                                       ocean_curl::float)
       +    freeboard = .1*ice_floe.thickness  # height above water
       +    rho_o = 1000.   # ocean density
       +    draft = ice_floe.thickness - freeboard  # height of submerged thickness
       +    c_o_v = .85  # ocean drag coefficient, vertical, Hunke and Comeau 2011
       +    c_o_h = 5e-4  # ocean drag coefficient, horizontal
       +
       +    ice_floe.torque +=
       +        pi*ice_floe.areal_radius^4.*rho_o*
       +        (ice_floe.areal_radius/5.*c_o_h + draft*c_o_h)*
       +        abs(.5*ocean_curl - ice_floe.ang_vel)*(.5*ocean_curl - ice_floe.ang_vel)
       +end
 (DIR) diff --git a/test/grid.jl b/test/grid.jl
       t@@ -137,3 +137,18 @@ SeaIce.addOceanDrag!(sim)
        @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")
       +ocean.u[1, 1, 1, 1] = 1.0
       +ocean.u[2, 1, 1, 1] = 1.0
       +ocean.u[2, 2, 1, 1] = 0.0
       +ocean.u[1, 2, 1, 1] = 0.0
       +ocean.v[:, :, 1, 1] = 0.0
       +@test SeaIce.curl(ocean, .5, .5, 1, 1, 1, 1) > 0.
       +
       +ocean.u[1, 1, 1, 1] = 0.0
       +ocean.u[2, 1, 1, 1] = 0.0
       +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.
 (DIR) diff --git a/test/ocean.jl b/test/ocean.jl
       t@@ -6,22 +6,126 @@
        info("#### $(basename(@__FILE__)) ####")
        
        info("Testing regular grid generation")
       -ocean = SeaIce.createRegularOceanGrid([6, 6, 6], [1., 1., 1.])
       -@test size(ocean.xq) == (7, 7)
       -@test size(ocean.yq) == (7, 7)
       -@test size(ocean.xh) == (6, 6)
       -@test size(ocean.yh) == (6, 6)
       -@test ocean.xq[1, :, 1] ≈ zeros(7)
       -@test ocean.xq[4, :, 1] ≈ .5*ones(7)
       -@test ocean.xq[end, :, 1] ≈ 1.*ones(7)
       -@test ocean.yq[:, 1, 1] ≈ zeros(7)
       -@test ocean.yq[:, 4, 1] ≈ .5*ones(7)
       -@test ocean.yq[:, end, 1] ≈ 1.*ones(7)
       -@test size(ocean.u) == (7, 7, 6, 1)
       -@test size(ocean.v) == (7, 7, 6, 1)
       -@test size(ocean.h) == (7, 7, 6, 1)
       -@test size(ocean.e) == (7, 7, 6, 1)
       -@test ocean.u ≈ zeros(7, 7, 6, 1)
       -@test ocean.v ≈ zeros(7, 7, 6, 1)
       -@test ocean.h ≈ zeros(7, 7, 6, 1)
       -@test ocean.e ≈ zeros(7, 7, 6, 1)
       +sim = SeaIce.createSimulation()
       +sim.ocean = SeaIce.createRegularOceanGrid([6, 6, 6], [1., 1., 1.])
       +@test size(sim.ocean.xq) == (7, 7)
       +@test size(sim.ocean.yq) == (7, 7)
       +@test size(sim.ocean.xh) == (6, 6)
       +@test size(sim.ocean.yh) == (6, 6)
       +@test sim.ocean.xq[1, :, 1] ≈ zeros(7)
       +@test sim.ocean.xq[4, :, 1] ≈ .5*ones(7)
       +@test sim.ocean.xq[end, :, 1] ≈ 1.*ones(7)
       +@test sim.ocean.yq[:, 1, 1] ≈ zeros(7)
       +@test sim.ocean.yq[:, 4, 1] ≈ .5*ones(7)
       +@test sim.ocean.yq[:, end, 1] ≈ 1.*ones(7)
       +@test size(sim.ocean.u) == (7, 7, 6, 1)
       +@test size(sim.ocean.v) == (7, 7, 6, 1)
       +@test size(sim.ocean.h) == (7, 7, 6, 1)
       +@test size(sim.ocean.e) == (7, 7, 6, 1)
       +@test sim.ocean.u ≈ zeros(7, 7, 6, 1)
       +@test sim.ocean.v ≈ zeros(7, 7, 6, 1)
       +@test sim.ocean.h ≈ zeros(7, 7, 6, 1)
       +@test sim.ocean.e ≈ zeros(7, 7, 6, 1)
       +
       +info("Testing velocity drag interaction (static ocean)")
       +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 ocean drag
       +
       +info("Testing velocity drag interaction (static ice floe)")
       +sim = deepcopy(sim_init)
       +sim.ocean.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 ocean drag
       +
       +info("Testing vortex interaction between (static ocean)")
       +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 ocean
       +@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 between (static ice floe)")
       +sim = deepcopy(sim_init)
       +sim.ocean = SeaIce.createRegularOceanGrid([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.ocean.v[1, :, 1, 1] = -0.1
       +sim.ocean.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 ocean vortex
       +@test E_kin_lin_init ≈ E_kin_lin_final  # no linear velocity gained
       +
       +sim = deepcopy(sim_init)
       +sim.ocean = SeaIce.createRegularOceanGrid([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.ocean.v[1, :, 1, 1] = 0.1
       +sim.ocean.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 ocean vortex
       +@test E_kin_lin_init ≈ E_kin_lin_final  # no linear velocity gained
       +
       +sim = deepcopy(sim_init)
       +sim.ocean = SeaIce.createRegularOceanGrid([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.ocean.u[:, 1, 1, 1] = -0.1
       +sim.ocean.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 ocean vortex
       +@test E_kin_lin_init ≈ E_kin_lin_final  # no linear velocity gained
       +
       +sim = deepcopy(sim_init)
       +sim.ocean = SeaIce.createRegularOceanGrid([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.ocean.u[:, 1, 1, 1] = 0.1
       +sim.ocean.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 ocean vortex
       +@test E_kin_lin_init ≈ E_kin_lin_final  # no linear velocity gained