seaice-experiments

sea ice experiments using Granular.jl
git clone git://src.adamsgaard.dk/seaice-experiments # fast
git clone https://src.adamsgaard.dk/seaice-experiments.git # slow
Log | Files | Refs | README | LICENSE Back to index

simulation.jl (14531B)


      1 #!/usr/bin/env julia
      2 import Granular
      3 import ArgParse
      4 
      5 verbose = false
      6 
      7 function parse_command_line()
      8     s = ArgParse.ArgParseSettings()
      9     ArgParse.@add_arg_table s begin
     10         "--width"
     11             help = "strait width [m]"
     12             arg_type = Float64
     13             default = 6e3
     14         "--E"
     15             help = "Young's modulus [Pa]"
     16             arg_type = Float64
     17             default = 2e7
     18         "--nu"
     19             help = "Poisson's ratio [-]"
     20             arg_type = Float64
     21             default = 0.285
     22         "--k_n"
     23             help = "normal stiffness [N/m]"
     24             arg_type = Float64
     25             default = 1e7
     26         "--k_t"
     27             help = "tangential stiffness [N/m]"
     28             arg_type = Float64
     29             default = 1e7
     30         "--gamma_n"
     31             help = "normal viscosity [N/(m/s)]"
     32             arg_type = Float64
     33             default = 0.
     34         "--gamma_t"
     35             help = "tangential viscosity [N/(m/s)]"
     36             arg_type = Float64
     37             default = 0.
     38         "--mu_s"
     39             help = "static friction coefficient [-]"
     40             arg_type = Float64
     41             default = 0.3
     42         "--mu_d"
     43             help = "dynamic friction coefficient [-]"
     44             arg_type = Float64
     45             default = 0.3
     46         "--mu_s_wall"
     47             help = "static friction coefficient for wall particles [-]"
     48             arg_type = Float64
     49             default = 0.3
     50         "--mu_d_wall"
     51             help = "dynamic friction coefficient for wall particles [-]"
     52             arg_type = Float64
     53             default = 0.3
     54         "--tensile_strength"
     55             help = "the maximum tensile strength [Pa]"
     56             arg_type = Float64
     57             default = 0.
     58         "--r_min"
     59             help = "minimum grain radius [m]"
     60             arg_type = Float64
     61             default = 6e2
     62         "--r_max"
     63             help = "maximum grain radius [m]"
     64             arg_type = Float64
     65             default = 1.35e3
     66         "--thickness"
     67             help = "grain thickness [m]"
     68             arg_type = Float64
     69             default = 1.
     70         "--rotating"
     71             help = "allow the grains to rotate"
     72             arg_type = Bool
     73             default = true
     74         "--ocean_vel_fac"
     75             help = "ocean velocity factor [-]"
     76             arg_type = Float64
     77             default = 0.0
     78         "--atmosphere_vel_fac"
     79             help = "atmosphere velocity [m/s]"
     80             arg_type = Float64
     81             default = 30.0
     82         "--total_hours"
     83             help = "hours of simulation time [h]"
     84             arg_type = Float64
     85             default = 12.
     86         "--seed"
     87             help = "seed for the pseudo RNG"
     88             arg_type = Int
     89             default = 1
     90         "id"
     91             help = "simulation id"
     92             required = true
     93     end
     94     return ArgParse.parse_args(s)
     95 end
     96 
     97 function report_args(parsed_args)
     98     println("Parsed args:")
     99     for (arg,val) in parsed_args
    100         println("  $arg  =>  $val")
    101     end
    102 end
    103 
    104 function run_simulation(id::String,
    105                         width::Float64,
    106                         E::Float64,
    107                         nu::Float64,
    108                         k_n::Float64,
    109                         k_t::Float64,
    110                         gamma_n::Float64,
    111                         gamma_t::Float64,
    112                         mu_s::Float64,
    113                         mu_d::Float64,
    114                         mu_s_wall::Float64,
    115                         mu_d_wall::Float64,
    116                         tensile_strength::Float64,
    117                         r_min::Float64,
    118                         r_max::Float64,
    119                         thickness::Float64,
    120                         rotating::Bool,
    121                         ocean_vel_fac::Float64,
    122                         atmosphere_vel_fac::Float64,
    123                         total_hours::Float64,
    124                         seed::Int)
    125 
    126     info("## EXPERIMENT: " * id * " ##")
    127     sim = Granular.createSimulation(id=id)
    128 
    129     const Lx = 50.e3
    130     const Lx_constriction = width
    131     const Ly_constriction = 10e3
    132     const L = [Lx, Lx*3./4., 1e3]
    133     const dx = r_max*2.
    134 
    135     #n = [Int(ceil(L[1]/dx/2.)), Int(ceil(L[2]/dx/2.)), 2]
    136     n = [Int(ceil(L[1]/dx)), Int(ceil(L[2]/dx)), 2]
    137 
    138     # Initialize confining walls, which are grains that are fixed in space
    139     r = r_max
    140     h = thickness
    141     r_walls = r_min/2.
    142 
    143     ## N-S segments
    144     for y in linspace(r_walls,
    145                       Ly_constriction - 2.0*r_walls, 
    146                       Int(ceil((Ly_constriction - 2.*r_walls)/(r_walls*2.))))
    147 
    148         Granular.addGrainCylindrical!(sim,
    149                                       [Lx/2. - Lx_constriction/2. - r_walls, y], 
    150                                       r_walls, h, fixed=true, verbose=false)
    151 
    152         Granular.addGrainCylindrical!(sim,
    153                                       [Lx/2. + Lx_constriction/2. + r_walls, y], 
    154                                       r_walls, h, fixed=true, verbose=false)
    155 
    156     end
    157 
    158     dx = 2.*r_walls
    159 
    160     ## Left island upper edge
    161     x = r_walls:dx:(Lx/2. - Lx_constriction/2. - r_walls)
    162     y = ones(length(x))*Ly_constriction
    163     for i in 1:length(x)
    164         Granular.addGrainCylindrical!(sim, [x[i], y[i]], r_walls, h, fixed=true, 
    165                                       verbose=false)
    166     end
    167 
    168     ## Right island upper edge
    169     x = (Lx/2. + Lx_constriction/2. + r_walls):dx:(Lx - r_walls)
    170     y = ones(length(x))*Ly_constriction
    171     for i in 1:length(x)
    172         Granular.addGrainCylindrical!(sim, [x[i], y[i]], r_walls, h, fixed=true, 
    173                                       verbose=false)
    174     end
    175 
    176     n_walls = length(sim.grains)
    177     info("added $(n_walls) fixed grains as walls")
    178 
    179     # Initialize ocean and atmosphere
    180     sim.ocean = Granular.createRegularOceanGrid(n, L, name="no_flow")
    181     sim.atmosphere = Granular.createRegularAtmosphereGrid(n, L, 
    182                                                           name="uniform_flow")
    183     sim.atmosphere.v[:, :, 1, 1] = -atmosphere_vel_fac
    184 
    185     Granular.setGridBoundaryConditions!(sim.ocean, "inactive", "-y +y")
    186     Granular.setGridBoundaryConditions!(sim.ocean, "impermeable", "-x +x")
    187 
    188     # Initialize grains in wedge north of the constriction
    189     Granular.sortGrainsInGrid!(sim, sim.ocean)
    190     iy = 1
    191     spacing_to_boundaries = r_walls
    192     floe_padding = .5*r
    193     noise_amplitude = floe_padding
    194     Base.Random.srand(seed)
    195     for iy=1:size(sim.ocean.xh, 2)
    196         for ix=1:size(sim.ocean.xh, 1)
    197 
    198             for it=1:25  # number of grains to try adding per cell
    199 
    200                 r_rand = r_min + Base.Random.rand()*(r - r_min)
    201                 pos = Granular.findEmptyPositionInGridCell(sim, sim.ocean,
    202                                                            ix, iy,
    203                                                            r_rand, n_iter=100,
    204                                                            seed=seed)
    205                 if !(typeof(pos) == Array{Float64, 1})
    206                     continue
    207                 end
    208 
    209                 @inbounds if pos[2] < Ly_constriction +
    210                     spacing_to_boundaries + r_rand
    211                     continue
    212                 end
    213                    
    214                 Granular.addGrainCylindrical!(sim, pos, r_rand, h, 
    215                                               verbose=false)
    216                 Granular.sortGrainsInGrid!(sim, sim.ocean)
    217             end
    218         end
    219     end
    220     n = length(sim.grains) - n_walls
    221     info("added $(n) grains")
    222 
    223     # Remove old simulation files
    224     Granular.removeSimulationFiles(sim)
    225 
    226     for i=1:length(sim.grains)
    227         sim.grains[i].youngs_modulus = E
    228         sim.grains[i].poissons_ratio = nu
    229         sim.grains[i].contact_stiffness_normal = k_n
    230         sim.grains[i].contact_stiffness_tangential = k_t
    231         sim.grains[i].contact_viscosity_normal = gamma_n
    232         sim.grains[i].contact_viscosity_tangential = gamma_t
    233         sim.grains[i].contact_static_friction = mu_s
    234         sim.grains[i].contact_dynamic_friction = mu_d
    235         sim.grains[i].tensile_strength = tensile_strength
    236         sim.grains[i].rotating = rotating
    237         if sim.grains[i].fixed == true
    238             sim.grains[i].contact_static_friction = mu_s_wall
    239             sim.grains[i].contact_dynamic_friction = mu_d_wall
    240         end
    241     end
    242 
    243     # Set temporal parameters
    244     Granular.setTotalTime!(sim, total_hours*60.*60.)
    245     #Granular.setOutputFileInterval!(sim, 60.*5.)  # output every 5 mins
    246     Granular.setOutputFileInterval!(sim, 60.)  # output every 1 mins
    247     Granular.setTimeStep!(sim, verbose=verbose)
    248     Granular.writeVTK(sim, verbose=verbose)
    249 
    250     println("$(sim.id) size before run")
    251     Granular.printMemoryUsage(sim)
    252 
    253     profile = false
    254 
    255     ice_flux = Float64[]
    256     avg_coordination_no = Float64[]
    257     #ice_flux_sample_points = 100
    258     #ice_flux = zeros(ice_flux_sample_points)
    259     #dt_ice_flux = sim.time_total/ice_flux_sample_points
    260     #time_since_ice_flux = 1e9
    261 
    262     jammed = false
    263     it_before_eval = 100
    264     time_jammed = 0.
    265     time_jammed_criterion = 60.*60.  # define as jammed after this duration
    266 
    267     # preallocate variables
    268     ice_mass_outside_domain = x = y = x_ = y_ = r_rand = 0.
    269 
    270     while sim.time < sim.time_total
    271 
    272         # run simulation for it_before_eval time steps
    273         for it=1:it_before_eval
    274             if sim.time >= sim.time_total*.75 && profile
    275                 @profile Granular.run!(sim, status_interval=1, single_step=true,
    276                                     verbose=verbose, show_file_output=verbose)
    277                 Profile.print()
    278                 profile = false
    279             else
    280                 Granular.run!(sim, status_interval=1, single_step=true,
    281                             verbose=verbose, show_file_output=verbose)
    282             end
    283         end
    284 
    285         if sim.time_iteration % 1_000 == 0
    286             @printf("\n%s size t=%5f h\n", sim.id, sim.time/3600.)
    287             Granular.printMemoryUsage(sim)
    288         end
    289 
    290         # assert if the system is jammed by looking at ice-floe mass change in 
    291         # the number of jammed grains
    292         if jammed
    293             time_jammed += sim.time_dt*float(it_before_eval)
    294             if time_jammed >= 60.*60.  # 1 h
    295                 info("$t s: system jammed for more than " * 
    296                 "$time_jammed_criterion s, stopping simulation")
    297                 exit()
    298             end
    299         end
    300 
    301         if sim.time_iteration % 1_000 == 0
    302             ice_mass_outside_domain = 0.
    303             for icefloe in sim.grains
    304                 if !icefloe.enabled
    305                     ice_mass_outside_domain += icefloe.mass
    306                 end
    307             end
    308             append!(ice_flux, ice_mass_outside_domain)
    309 
    310             # get average coordination number around channel entrance
    311             n_contacts_sum = 0
    312             n_particles = 0
    313             for i=1:length(sim.grains)
    314                 if !sim.grains[i].fixed && sim.grains[i].enabled
    315                     n_contacts_sum += sim.grains[i].n_contacts
    316                     n_particles += 1
    317                 end
    318             end
    319             append!(avg_coordination_no, float(n_contacts_sum/n_particles))
    320         end
    321 
    322         # add new grains from the top
    323         @inbounds for ix=2:(size(sim.ocean.xh, 1) - 1)
    324             if length(sim.ocean.grain_list[ix, end]) == 0
    325                 for it=1:17  # number of grains to try adding per cell
    326                     # Uniform distribution
    327                     #r_rand = r_min + Base.Random.rand()*(r_max - r_min)
    328 
    329                     # Exponential distribution with scale=1
    330                     #r_rand = r_min + Base.Random.randexp()*(r_max - r_min)/4.
    331 
    332                     # Power-law distribution (sea ice power ≈ -1.8)
    333                     r_rand = Granular.randpower(1, -1.8, r_min, r_max)
    334 
    335                     pos = Granular.findEmptyPositionInGridCell(sim, sim.ocean,
    336                                                              ix, iy,
    337                                                              r_rand, n_iter=100)
    338                     if !(typeof(pos) == Array{Float64, 1})
    339                         continue
    340                     end
    341 
    342                     Granular.addGrainCylindrical!(sim, pos, r_rand, h, 
    343                                                   verbose=false,
    344                                                   youngs_modulus=E,
    345                                                   poissons_ratio=nu,
    346                                                   contact_stiffness_normal=k_n,
    347                                                   contact_stiffness_tangential=
    348                                                   k_t,
    349                                                   contact_viscosity_normal=
    350                                                   gamma_n,
    351                                                   contact_viscosity_tangential=
    352                                                   gamma_t,
    353                                                   contact_static_friction=mu_s,
    354                                                   contact_dynamic_friction=
    355                                                   mu_d,
    356                                                   tensile_strength=
    357                                                   tensile_strength,
    358                                                   rotating=rotating)
    359                     Granular.sortGrainsInGrid!(sim, sim.ocean)
    360                 end
    361             end
    362         end
    363 
    364     end
    365 
    366     Granular.writeParaviewPythonScript(sim)
    367     t = linspace(0., sim.time_total, length(ice_flux))
    368     writedlm(sim.id * "-ice-flux.txt", [t, ice_flux, avg_coordination_no])
    369     sim = 0
    370     gc()
    371 end
    372 
    373 function main()
    374     parsed_args = parse_command_line()
    375     report_args(parsed_args)
    376 
    377     seed = parsed_args["seed"]
    378 
    379     run_simulation(parsed_args["id"] * "-seed" * string(seed),
    380                    parsed_args["width"],
    381                    parsed_args["E"],
    382                    parsed_args["nu"],
    383                    parsed_args["k_n"],
    384                    parsed_args["k_t"],
    385                    parsed_args["gamma_n"],
    386                    parsed_args["gamma_t"],
    387                    parsed_args["mu_s"],
    388                    parsed_args["mu_d"],
    389                    parsed_args["mu_s_wall"],
    390                    parsed_args["mu_d_wall"],
    391                    parsed_args["tensile_strength"],
    392                    parsed_args["r_min"],
    393                    parsed_args["r_max"],
    394                    parsed_args["thickness"],
    395                    parsed_args["rotating"],
    396                    parsed_args["ocean_vel_fac"],
    397                    parsed_args["atmosphere_vel_fac"],
    398                    parsed_args["total_hours"],
    399                    seed)
    400 end
    401 
    402 main()