| tsimulation.jl - seaice-experiments - sea ice experiments using Granular.jl | |
| git clone git://src.adamsgaard.dk/seaice-experiments | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| tsimulation.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 spa… | |
| 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_wa… | |
| 150 r_walls, h, fixed=true, verbose=fa… | |
| 151 | |
| 152 Granular.addGrainCylindrical!(sim, | |
| 153 [Lx/2. + Lx_constriction/2. + r_wa… | |
| 154 r_walls, h, fixed=true, verbose=fa… | |
| 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, fix… | |
| 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, fix… | |
| 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_… | |
| 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.ocea… | |
| 202 ix, iy, | |
| 203 r_rand, n_ite… | |
| 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 durat… | |
| 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_st… | |
| 276 verbose=verbose, show_file_output=ve… | |
| 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 cha… | |
| 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_particle… | |
| 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_m… | |
| 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.… | |
| 336 ix, iy, | |
| 337 r_rand, n_i… | |
| 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_norm… | |
| 347 contact_stiffness_tang… | |
| 348 k_t, | |
| 349 contact_viscosity_norm… | |
| 350 gamma_n, | |
| 351 contact_viscosity_tang… | |
| 352 gamma_t, | |
| 353 contact_static_frictio… | |
| 354 contact_dynamic_fricti… | |
| 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() |