tjamming-ocean-atmosphere.jl - seaice-experiments - sea ice experiments using Granular.jl
 (HTM) git clone git://src.adamsgaard.dk/seaice-experiments
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       tjamming-ocean-atmosphere.jl (16831B)
       ---
            1 #!/usr/bin/env julia
            2 import Granular
            3 import ArgParse
            4 import Plots
            5 
            6 verbose = false
            7 
            8 function parse_command_line()
            9     s = ArgParse.ArgParseSettings()
           10     ArgParse.@add_arg_table s begin
           11         "--width"
           12             help = "strait width [m]"
           13             arg_type = Float64
           14             default = 5e3
           15         "--E"
           16             help = "Young's modulus [Pa]"
           17             arg_type = Float64
           18             default = 0.
           19         "--nu"
           20             help = "Poisson's ratio [-]"
           21             arg_type = Float64
           22             default = 0.
           23         "--k_n"
           24             help = "normal stiffness [N/m]"
           25             arg_type = Float64
           26             default = 1e7
           27         "--k_t"
           28             help = "tangential stiffness [N/m]"
           29             arg_type = Float64
           30             default = 1e7
           31         "--gamma_n"
           32             help = "normal viscosity [N/(m/s)]"
           33             arg_type = Float64
           34             default = 0.
           35         "--gamma_t"
           36             help = "tangential viscosity [N/(m/s)]"
           37             arg_type = Float64
           38             default = 0.
           39         "--mu_s"
           40             help = "static friction coefficient [-]"
           41             arg_type = Float64
           42             default = 0.5
           43         "--mu_d"
           44             help = "dynamic friction coefficient [-]"
           45             arg_type = Float64
           46             default = 0.5
           47         "--mu_s_wall"
           48             help = "static friction coefficient for wall particles [-]"
           49             arg_type = Float64
           50             default = 0.5
           51         "--mu_d_wall"
           52             help = "dynamic friction coefficient for wall particles [-]"
           53             arg_type = Float64
           54             default = 0.5
           55         "--tensile_strength"
           56             help = "the maximum tensile strength [Pa]"
           57             arg_type = Float64
           58             default = 0.
           59         "--r_min"
           60             help = "minimum grain radius [m]"
           61             arg_type = Float64
           62             default = 1e3
           63         "--r_max"
           64             help = "maximum grain radius [m]"
           65             arg_type = Float64
           66             default = 1e3
           67         "--rotating"
           68             help = "allow the grains to rotate"
           69             arg_type = Bool
           70             default = true
           71         "--ocean_vel_fac"
           72             help = "ocean velocity factor [-]"
           73             arg_type = Float64
           74             default = 1e4
           75         "--atmosphere_vel_fac"
           76             help = "atmosphere velocity [m/s]"
           77             arg_type = Float64
           78             default = 2.0
           79         "--total_hours"
           80             help = "hours of simulation time [h]"
           81             arg_type = Float64
           82             default = 6.
           83         "--nruns"
           84             help = "number of runs in ensemble"
           85             arg_type = Int
           86             default = 1
           87         "id"
           88             help = "simulation id"
           89             required = true
           90     end
           91     return ArgParse.parse_args(s)
           92 end
           93 
           94 function report_args(parsed_args)
           95     println("Parsed args:")
           96     for (arg,val) in parsed_args
           97         println("  $arg  =>  $val")
           98     end
           99 end
          100 
          101 function run_simulation(id::String,
          102                         width::Float64,
          103                         E::Float64,
          104                         nu::Float64,
          105                         k_n::Float64,
          106                         k_t::Float64,
          107                         gamma_n::Float64,
          108                         gamma_t::Float64,
          109                         mu_s::Float64,
          110                         mu_d::Float64,
          111                         mu_s_wall::Float64,
          112                         mu_d_wall::Float64,
          113                         tensile_strength::Float64,
          114                         r_min::Float64,
          115                         r_max::Float64,
          116                         rotating::Bool,
          117                         ocean_vel_fac::Float64,
          118                         atmosphere_vel_fac::Float64,
          119                         total_hours::Float64,
          120                         seed::Int)
          121 
          122     info("## EXPERIMENT: " * id * " ##")
          123     sim = Granular.createSimulation(id=id)
          124 
          125     Lx = 50.e3
          126     Lx_constriction = width
          127     L = [Lx, Lx*1.5, 1e3]
          128     Ly_constriction = 20e3
          129     dx = r_max*2.
          130 
          131     n = [Int(ceil(L[1]/dx/2.)), Int(ceil(L[2]/dx/2.)), 2]
          132 
          133     # Initialize confining walls, which are grains that are fixed in space
          134     r = r_max
          135     r_min = r/4.
          136     h = 1.
          137     r_walls = r_min
          138 
          139     ## N-S segments
          140     for y in linspace((L[2] - Ly_constriction)/2.,
          141                       Ly_constriction + (L[2] - Ly_constriction)/2., 
          142                       Int(round(Ly_constriction/(r_walls*2))))
          143         Granular.addGrainCylindrical!(sim, [(Lx - Lx_constriction)/2., y], 
          144                                      r_walls, h, fixed=true, verbose=false)
          145     end
          146     for y in linspace((L[2] - Ly_constriction)/2.,
          147                       Ly_constriction + (L[2] - Ly_constriction)/2., 
          148                       Int(round(Ly_constriction/(r_walls*2))))
          149         Granular.addGrainCylindrical!(sim, [Lx_constriction + (L[1] - 
          150                                       Lx_constriction)/2., y], r_walls, h, 
          151                                      fixed=true, verbose=false)
          152     end
          153 
          154     dx = 2.*r_walls*sin(atan((Lx - Lx_constriction)/(L[2] - Ly_constriction)))
          155 
          156     ## NW diagonal
          157     x = r_walls:dx:((Lx - Lx_constriction)/2.)
          158     y = linspace(L[2] - r_walls, (L[2] - Ly_constriction)/2. + Ly_constriction + 
          159                  r_walls, length(x))
          160     for i in 1:length(x)
          161         Granular.addGrainCylindrical!(sim, [x[i], y[i]], r_walls, h, fixed=true, 
          162                                      verbose=false)
          163     end
          164 
          165     ## NE diagonal
          166     x = (L[1] - r_walls):(-dx):((Lx - Lx_constriction)/2. + Lx_constriction)
          167     y = linspace(L[2] - r_walls, (L[2] - Ly_constriction)/2. + Ly_constriction + 
          168                  r_walls, length(x))
          169     for i in 1:length(x)
          170         Granular.addGrainCylindrical!(sim, [x[i], y[i]], r_walls, h, fixed=true, 
          171                                      verbose=false)
          172     end
          173 
          174     ## SW diagonal
          175     x = r_walls:dx:((Lx - Lx_constriction)/2.)
          176     y = linspace(r, (L[2] - Ly_constriction)/2. - r_walls, length(x))
          177     for i in 1:length(x)
          178         Granular.addGrainCylindrical!(sim, [x[i], y[i]], r_walls, h, fixed=true, 
          179                                      verbose=false)
          180     end
          181 
          182     ## SE diagonal
          183     x = (L[1] - r_walls):(-dx):((Lx - Lx_constriction)/2. + Lx_constriction)
          184     y = linspace(r_walls, (L[2] - Ly_constriction)/2. - r_walls, length(x))
          185     for i in 1:length(x)
          186         Granular.addGrainCylindrical!(sim, [x[i], y[i]], r_walls, h, fixed=true, 
          187                                      verbose=false)
          188     end
          189 
          190     n_walls = length(sim.grains)
          191     info("added $(n_walls) fixed grains as walls")
          192 
          193     # Initialize ocean
          194     sim.ocean = Granular.createRegularOceanGrid(n, L, name="poiseuille_flow")
          195 
          196     # Determine stream function value for all grid cells, row by row.
          197     # At y=0 and y=Ly:  psi = a*ocean_vel_fac*(x - Lx/2.).^3 with a = 1.
          198     # The value of a increases when strait is narrow, and psi values are 
          199     # constant outside domain>
          200     psi = similar(sim.ocean.v[:, :, 1, 1])
          201     Granular.sortGrainsInGrid!(sim, sim.ocean)
          202     for j=1:size(psi, 2)
          203 
          204         # Check width of domain in the current row
          205         if sim.ocean.yq[1, j] < (L[2] - Ly_constriction)/2.
          206             # lower triangle
          207             W = (Lx - width)*
          208                 (1. - sim.ocean.yq[1, j]/((L[2] - Ly_constriction)/2.)) + width
          209 
          210         elseif sim.ocean.yq[1, j] < Ly_constriction+(L[2] - Ly_constriction)/2.  
          211             # strait
          212             W = width
          213 
          214         else
          215             y_min = Ly_constriction + (L[2] - Ly_constriction)/2.
          216 
          217             # upper triangle
          218             W = (Lx - width)*(sim.ocean.yq[1, j] - y_min)/(L[2] - y_min) + width
          219         end
          220 
          221         # transform [Lx/2 - W/2; Lx/2 + W/2] to [-2;2]
          222         x_ = (sim.ocean.xq[:, j] - (Lx/2. - W/2.))/W*4. - 2.
          223 
          224         psi[:, j] = tanh(x_)
          225     end
          226 
          227     # determine ocean velocities (u and v) from stream function derivatives
          228     for i=1:size(psi, 1)
          229         if i == 1
          230             sim.ocean.v[i, :, 1, 1] = -(psi[i+1, :] - psi[i, :])./
          231                 (sim.ocean.xq[i+1, :] - sim.ocean.xq[i, :])
          232         elseif i == size(psi, 1)
          233             sim.ocean.v[i, :, 1, 1] = -(psi[i, :] - psi[i-1, :])./
          234                 (sim.ocean.xq[i, :] - sim.ocean.xq[i-1, :])
          235         else
          236             sim.ocean.v[i, :, 1, 1] = -(psi[i+1, :] - psi[i-1, :])./
          237                 (sim.ocean.xq[i+1, :] - sim.ocean.xq[i-1, :])
          238         end
          239     end
          240 
          241     for j=1:size(psi, 2)
          242         if j == 1
          243             sim.ocean.u[:, j, 1, 1] = (psi[:, j+1] - psi[:, j])./
          244                 (sim.ocean.yq[:, j+1] - sim.ocean.yq[:, j])
          245         elseif j == size(psi, 2)
          246             sim.ocean.u[:, j, 1, 1] = (psi[:, j] - psi[:, j-1])./
          247                 (sim.ocean.yq[:, j] - sim.ocean.yq[:, j-1])
          248         else
          249             sim.ocean.u[:, j, 1, 1] = (psi[:, j+1] - psi[:, j-1])./
          250                 (sim.ocean.yq[:, j+1] - sim.ocean.yq[:, j-1])
          251         end
          252     end
          253     sim.ocean.h[:,:,1,1] = psi  # this field is unused; use for stream function
          254     sim.ocean.u *= ocean_vel_fac
          255     sim.ocean.v *= ocean_vel_fac
          256 
          257     # Constant velocities along y:
          258     #sim.ocean.v[:, :, 1, 1] = ocean_vel_fac*((sim.ocean.xq - Lx/2.).^2 - 
          259     #                                        Lx^2./4.)
          260     sim.atmosphere = Granular.createRegularAtmosphereGrid(n, L, 
          261                                                         name="uniform_flow")
          262     sim.atmosphere.v[:, :, 1, 1] = -atmosphere_vel_fac
          263 
          264     # Initialize grains in wedge north of the constriction
          265     iy = 1
          266     dy = sqrt((2.*r_walls)^2. - dx^2.)
          267     spacing_to_boundaries = 2.*r
          268     floe_padding = .5*r
          269     noise_amplitude = floe_padding
          270     Base.Random.srand(seed)
          271     for y in (L[2] - r - noise_amplitude):(-(2.*r + floe_padding)):((L[2] - 
          272         Ly_constriction)/2. + Ly_constriction)
          273         for x in (r + noise_amplitude):(2.*r + floe_padding):(Lx - r - 
          274                                                               noise_amplitude)
          275             if iy % 2 == 0
          276                 x += 1.5*r
          277             end
          278 
          279             x_ = x + noise_amplitude*(0.5 - Base.Random.rand())
          280             y_ = y + noise_amplitude*(0.5 - Base.Random.rand())
          281 
          282             if y_ < -dy/dx*x_ + L[2] + spacing_to_boundaries
          283                 continue
          284             end
          285                 
          286             if y_ < dy/dx*x_ + (L[2] - dy/dx*Lx) + spacing_to_boundaries
          287                 continue
          288             end
          289                 
          290             r_rand = r_min + Base.Random.rand()*(r - r_min)
          291             Granular.addGrainCylindrical!(sim, [x_, y_], r_rand, h, 
          292                                          verbose=false)
          293         end
          294         iy += 1
          295     end
          296     n = length(sim.grains) - n_walls
          297     info("added $(n) grains")
          298 
          299     # Remove old simulation files
          300     Granular.removeSimulationFiles(sim)
          301 
          302     for i=1:length(sim.grains)
          303         sim.grains[i].youngs_modulus = E
          304         sim.grains[i].poissons_ratio = nu
          305         sim.grains[i].contact_stiffness_normal = k_n
          306         sim.grains[i].contact_stiffness_tangential = k_t
          307         sim.grains[i].contact_viscosity_normal = gamma_n
          308         sim.grains[i].contact_viscosity_tangential = gamma_t
          309         sim.grains[i].contact_static_friction = mu_s
          310         sim.grains[i].contact_dynamic_friction = mu_d
          311         sim.grains[i].tensile_strength = tensile_strength
          312         sim.grains[i].rotating = rotating
          313         if sim.grains[i].fixed == true
          314             sim.grains[i].contact_static_friction = mu_s_wall
          315             sim.grains[i].contact_dynamic_friction = mu_d_wall
          316         end
          317     end
          318 
          319     # Set temporal parameters
          320     Granular.setTotalTime!(sim, total_hours*60.*60.)
          321     #Granular.setOutputFileInterval!(sim, 60.*5.)  # output every 5 mins
          322     Granular.setOutputFileInterval!(sim, 60.)  # output every 1 mins
          323     Granular.setTimeStep!(sim, verbose=verbose)
          324     Granular.writeVTK(sim, verbose=verbose)
          325 
          326     profile = false
          327 
          328     ice_flux = Float64[]
          329     jammed = false
          330     it_before_eval = 10
          331     time_jammed = 0.
          332     time_jammed_criterion = 60.*60.  # define as jammed after this duration
          333 
          334     while sim.time < sim.time_total
          335 
          336         # run simulation for it_before_eval time steps
          337         for it=1:it_before_eval
          338             if sim.time >= sim.time_total*.75 && profile
          339                 @profile Granular.run!(sim, status_interval=1, single_step=true,
          340                                     verbose=verbose, show_file_output=verbose)
          341                 Profile.print()
          342                 profile = false
          343             else
          344                 Granular.run!(sim, status_interval=1, single_step=true,
          345                             verbose=verbose, show_file_output=verbose)
          346             end
          347         end
          348 
          349         # assert if the system is jammed by looking at ice-floe mass change in 
          350         # the number of jammed grains
          351         if jammed
          352             time_jammed += sim.time_dt*float(it_before_eval)
          353             if time_jammed >= 60.*60.  # 1 h
          354                 info("$t s: system jammed for more than " * 
          355                 "$time_jammed_criterion s, stopping simulation")
          356                 exit()
          357             end
          358         end
          359 
          360         ice_mass_outside_domain = 0.
          361         for icefloe in sim.grains
          362             if !icefloe.enabled
          363                 ice_mass_outside_domain += icefloe.mass
          364             end
          365         end
          366         append!(ice_flux, ice_mass_outside_domain)
          367 
          368         # add new grains from the top
          369         for i=1:size(sim.ocean.xh, 1)
          370             if sim.ocean.grain_list[i, end] == []
          371 
          372                 x, y = Granular.getCellCenterCoordinates(sim.ocean, i, 
          373                                                        size(sim.ocean.xh, 2))
          374 
          375                 x_ = x + noise_amplitude*(0.5 - Base.Random.rand())
          376                 y_ = y + noise_amplitude*(0.5 - Base.Random.rand())
          377                 r_rand = r_min + Base.Random.rand()*(r - r_min)
          378 
          379                 Granular.addGrainCylindrical!(sim, [x_, y_], r_rand, h, 
          380                         verbose=false,
          381                         youngs_modulus=E,
          382                         poissons_ratio=nu,
          383                         contact_stiffness_normal=k_n,
          384                         contact_stiffness_tangential=k_t,
          385                         contact_viscosity_normal=gamma_n,
          386                         contact_viscosity_tangential=gamma_t,
          387                         contact_static_friction = mu_s,
          388                         contact_dynamic_friction = mu_d,
          389                         tensile_strength = tensile_strength,
          390                         rotating=rotating)
          391             end
          392         end
          393     end
          394 
          395     t = linspace(0., sim.time_total, length(ice_flux))
          396     writedlm(sim.id * "-ice-flux.txt", [t, ice_flux])
          397     return t, ice_flux
          398 end
          399 
          400 function main()
          401     parsed_args = parse_command_line()
          402     report_args(parsed_args)
          403 
          404     nruns = parsed_args["nruns"]
          405     t = Float64[]
          406     t_jam = ones(nruns)*parsed_args["total_hours"]*60.*60.*2.
          407     Plots.gr()
          408 
          409     for i=1:nruns
          410         seed = i
          411         t, ice_flux = run_simulation(parsed_args["id"] * "-seed" * string(seed),
          412                                      parsed_args["width"],
          413                                      parsed_args["E"],
          414                                      parsed_args["nu"],
          415                                      parsed_args["k_n"],
          416                                      parsed_args["k_t"],
          417                                      parsed_args["gamma_n"],
          418                                      parsed_args["gamma_t"],
          419                                      parsed_args["mu_s"],
          420                                      parsed_args["mu_d"],
          421                                      parsed_args["mu_s_wall"],
          422                                      parsed_args["mu_d_wall"],
          423                                      parsed_args["tensile_strength"],
          424                                      parsed_args["r_min"],
          425                                      parsed_args["r_max"],
          426                                      parsed_args["rotating"],
          427                                      parsed_args["ocean_vel_fac"],
          428                                      parsed_args["atmosphere_vel_fac"],
          429                                      parsed_args["total_hours"],
          430                                      i)
          431         Plots.plot!(t/(60.*60.), ice_flux)
          432 
          433         time_elapsed_while_jammed = 0.
          434         for it=(length(t) - 1):-1:1
          435             if ice_flux[it] ≈ ice_flux[end]
          436                 time_elapsed_while_jammed = t[end] - t[it]
          437             end
          438         end
          439 
          440         if time_elapsed_while_jammed > 60.*60.
          441             t_jam[i] = t[end] - time_elapsed_while_jammed
          442             info("simulation $i jammed at t = $(t_jam[i]/(60.*60.)) h")
          443         end
          444 
          445     end
          446     Plots.title!(parsed_args["id"])
          447     Plots.xaxis!("Time [h]")
          448     Plots.yaxis!("Cumulative ice throughput [kg]")
          449 
          450     Plots.savefig(parsed_args["id"])
          451     Plots.closeall()
          452 
          453     jam_fraction = zeros(length(t))
          454     for it=1:length(t)
          455         for i=1:nruns
          456             if t_jam[i] <= t[it]
          457                 jam_fraction[it] += 1./float(nruns)
          458             end
          459         end
          460     end
          461     Plots.plot(t/(60.*60.), jam_fraction)
          462     Plots.title!(parsed_args["id"] * ", N = " * string(nruns))
          463     Plots.xaxis!("Time [h]")
          464     Plots.yaxis!("Fraction of runs jammed [-]")
          465     Plots.savefig(parsed_args["id"] * "-jam_fraction.pdf")
          466 end
          467 
          468 main()