Granular.jl

Julia package for granular dynamics simulation
git clone git://src.adamsgaard.dk/Granular.jl
Log | Files | Refs | README | LICENSE

commit 639cc9a7b7cdaf8f547341187bdc9b204473b66e
parent ec8211d8369f687eb8c6ac01638559c5809c203e
Author: Anders Damsgaard <andersd@riseup.net>
Date:   Fri,  2 Jun 2017 15:36:53 -0400

begin implementing atmosphere drag

Diffstat:
Msrc/SeaIce.jl | 1+
Asrc/atmosphere.jl | 213+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/datatypes.jl | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/grid.jl | 40++++++++++++++++++++--------------------
Msrc/icefloe.jl | 24++++++++++++++----------
Msrc/io.jl | 69+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Msrc/simulation.jl | 10+++++++---
7 files changed, 384 insertions(+), 44 deletions(-)

diff --git a/src/SeaIce.jl b/src/SeaIce.jl @@ -18,5 +18,6 @@ include("temporal.jl") include("temporal_integration.jl") include("io.jl") include("ocean.jl") +include("atmosphere.jl") end # module end diff --git a/src/atmosphere.jl b/src/atmosphere.jl @@ -0,0 +1,213 @@ +export createEmptyAtmosphere +"Returns empty ocean type for initialization purposes." +function createEmptyAtmosphere() + return Atmosphere(false, + + zeros(1), + + zeros(1,1), + zeros(1,1), + zeros(1,1), + zeros(1,1), + + zeros(1), + + zeros(1,1,1,1), + zeros(1,1,1,1), + + Array{Array{Int, 1}}(1, 1)) +end + +export interpolateAtmosphereVelocitiesToCorners +""" +Convert gridded data from Arakawa-C type (decomposed velocities at faces) to +Arakawa-B type (velocities at corners) through interpolation. +""" +function interpolateAtmosphereVelocitiesToCorners(u_in::Array{float, 4}, + v_in::Array{float, 4}) + + if size(u_in) != size(v_in) + error("size of u_in ($(size(u_in))) must match v_in ($(size(v_in)))") + end + + nx, ny, nz, nt = size(u_in) + #u = Array{float}(nx+1, ny+1, nz, nt) + #v = Array{float}(nx+1, ny+1, nz, nt) + u = zeros(nx+1, ny+1, nz, nt) + v = zeros(nx+1, ny+1, nz, nt) + for i=1:nx + for j=1:ny + if j < ny - 1 + u[i, j, :, :] = (u_in[i, j, :, :] + u_in[i, j+1, :, :])/2. + else + u[i, j, :, :] = u_in[i, j, :, :] + end + if i < nx - 1 + v[i, j, :, :] = (v_in[i, j, :, :] + v_in[i+1, j, :, :])/2. + else + v[i, j, :, :] = v_in[i, j, :, :] + end + end + end + return u, v +end + +export interpolateAtmosphereState +""" +Atmosphere data is containted in `Atmosphere` type at discrete times +(`Atmosphere.time`). This function performs linear interpolation between time +steps to get the approximate atmosphere state at any point in time. If the +`Atmosphere` data set only contains a single time step, values from that time +are returned. +""" +function interpolateAtmosphereState(atmosphere::Atmosphere, t::float) + if length(atmosphere.time) == 1 + return atmosphere.u, atmosphere.v + elseif t < atmosphere.time[1] || t > atmosphere.time[end] + error("selected time (t = $(t)) is outside the range of time steps in + the atmosphere data") + end + + i = 1 + rel_time = 0. + while i < length(atmosphere.time) + if atmosphere.time[i+1] < t + i += 1 + continue + end + + dt = atmosphere.time[i+1] - atmosphere.time[i] + rel_time = (t - atmosphere.time[i])/dt + if rel_time < 0. || rel_time > 1. + error("time bounds error") + end + break + end + + return atmosphere.u[:,:,:,i]*(1. - rel_time) + + atmosphere.u[:,:,:,i+1]*rel_time, + atmosphere.v[:,:,:,i]*(1. - rel_time) + + atmosphere.v[:,:,:,i+1]*rel_time +end + +export createRegularAtmosphereGrid +""" +Initialize and return a regular, Cartesian `Atmosphere` grid with `n[1]` by `n[2]` +cells in the horizontal dimension, and `n[3]` vertical cells. The cell corner +and center coordinates will be set according to the grid spatial dimensions +`L[1]`, `L[2]`, and `L[3]`. The grid `u`, `v`, `h`, and `e` fields will contain +one 4-th dimension matrix per `time` step. Sea surface will be at `z=0.` with +the atmosphere spanning `z<0.`. Vertical indexing starts with `k=0` at the sea +surface, and increases downwards. +""" +function createRegularAtmosphereGrid(n::Array{Int, 1}, + L::Array{float, 1}; + origo::Array{float, 1} = zeros(2), + time::Array{float, 1} = zeros(1), + name::String = "unnamed") + + xq = repmat(linspace(origo[1], L[1], n[1] + 1), 1, n[2] + 1) + yq = repmat(linspace(origo[2], L[2], n[2] + 1)', n[1] + 1, 1) + + dx = L./n + xh = repmat(linspace(origo[1] + .5*dx[1], L[1] - .5*dx[1], n[1]), 1, n[2]) + 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, + Array{Array{Int, 1}}(size(xh, 1), size(xh, 2))) +end + +export addAtmosphereDrag! +""" +Add drag from linear and angular velocity difference between atmosphere and all +ice floes. +""" +function addAtmosphereDrag!(simulation::Simulation) + if typeof(simulation.atmosphere.input_file) == Bool + error("no atmosphere data read") + end + + u, v, h, e = interpolateAtmosphereState(simulation.atmosphere, + simulation.time) + + for ice_floe in simulation.ice_floes + + if !ice_floe.enabled + continue + end + + i, j = ice_floe.atmosphere_grid_pos + k = 1 + + x_tilde, y_tilde = getNonDimensionalCellCoordinates(simulation. + atmosphere, + i, j, + ice_floe.lin_pos) + if x_tilde < 0. || x_tilde > 1. || y_tilde < 0. || y_tilde > 1. + warn(""" + relative coordinates outside bounds ($(x_tilde), $(y_tilde)), + pos = $(ice_floe.lin_pos) at i,j = $(i), $(j). + + """) + end + + 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.atmosphere, x_tilde, y_tilde, i, j, k, 1) + + applyAtmosphereDragToIceFloe!(ice_floe, u_local, v_local) + applyAtmosphereVorticityToIceFloe!(ice_floe, vel_curl) + end +end + +export applyAtmosphereDragToIceFloe! +""" +Add Stokes-type drag from velocity difference between atmosphere and a single +ice floe. +""" +function applyAtmosphereDragToIceFloe!(ice_floe::IceFloeCylindrical, + u::float, v::float) + freeboard = .1*ice_floe.thickness # height above water + rho_a = 1000. # atmosphere density + draft = ice_floe.thickness - freeboard # height of submerged thickness + length = ice_floe.areal_radius*2. + width = ice_floe.areal_radius*2. + + ice_floe.force += + rho_a * (.5*ice_floe.ocean_drag_coeff_vert*width*draft + + ice_floe.atmosphere_drag_coeff_horiz*length*width) * + ([u, v] - ice_floe.lin_vel)*norm([u, v] - ice_floe.lin_vel) +end + +export applyAtmosphereVorticityToIceFloe! +""" +Add Stokes-type torque from angular velocity difference between atmosphere and a +single ice floe. See Eq. 9.28 in "Introduction to Fluid Mechanics" by Nakayama +and Boucher, 1999. +""" +function applyAtmosphereVorticityToIceFloe!(ice_floe::IceFloeCylindrical, + atmosphere_curl::float) + freeboard = .1*ice_floe.thickness # height above water + rho_a = 1000. # atmosphere density + draft = ice_floe.thickness - freeboard # height of submerged thickness + + ice_floe.torque += + pi*ice_floe.areal_radius^4.*rho_o* + (ice_floe.areal_radius/5.*ice_floe.atmosphere_drag_coeff_horiz + + draft*ice_floe.atmosphere_drag_coeff_vert)* + abs(.5*atmosphere_curl - ice_floe.ang_vel)* + (.5*atmosphere_curl - ice_floe.ang_vel) +end diff --git a/src/datatypes.jl b/src/datatypes.jl @@ -53,13 +53,14 @@ type IceFloeCylindrical # Ocean/atmosphere interaction parameters ocean_drag_coeff_vert::float ocean_drag_coeff_horiz::float - atmos_drag_coeff_vert::float - atmos_drag_coeff_horiz::float + atmosphere_drag_coeff_vert::float + atmosphere_drag_coeff_horiz::float # Interaction pressure::float n_contacts::Int ocean_grid_pos::Array{Int, 1} + atmosphere_grid_pos::Array{Int, 1} contacts::Array{Int, 1} contact_parallel_displacement::Array{Array{Float64, 1}, 1} contact_age::Array{Float64, 1} @@ -114,8 +115,8 @@ type IceFloeArrays ocean_drag_coeff_vert ocean_drag_coeff_horiz - atmos_drag_coeff_vert - atmos_drag_coeff_horiz + atmosphere_drag_coeff_vert + atmosphere_drag_coeff_horiz pressure n_contacts @@ -123,7 +124,7 @@ end #= Type containing all relevant data from MOM6 NetCDF files. The ocean grid is a -staggered of Arakawa-C type, with south-west convention centered on the +staggered of Arakawa-B type, with south-west convention centered on the h-points. During read, the velocities are interpolated to the cell corners (q-points). @@ -156,8 +157,8 @@ h-points. During read, the velocities are interpolated to the cell corners placement in `[xh, yh, zl, time]`. * `e::Array{Float64, Int}`: interface height relative to mean sea level [m], dimensions correspond to placement in `[xh, yh, zi, time]`. -* `ice_floe_list::Array{Float64, Int}`: interface height relative to mean sea - level [m], dimensions correspond to placement in `[xh, yh, zi, time]`. +* `ice_floe_list::Array{Float64, Int}`: indexes of ice floes contained in the + ocean grid cells. =# type Ocean input_file::Any @@ -185,6 +186,61 @@ type Ocean ice_floe_list::Array{Array{Int, 1}, 2} end +#= +The atmosphere grid is a staggered of Arakawa-B type, with south-west convention +centered on the h-points. During read, the velocities are interpolated to the +cell corners (q-points). + + q( i,j+1) ------------------ q(i+1,j+1) + | | + | | + | | + | | + | h( i, j) | + | | + | | + | | + | | + q( i, j) ------------------ q(i+1, j) + +# Fields +* `input_file::String`: path to input NetCDF file +* `time::Array{Float64, 1}`: time in days +* `xq::Array{Float64, 1}`: nominal longitude of q-points [degrees_E] +* `yq::Array{Float64, 1}`: nominal latitude of q-points [degrees_N] +* `xh::Array{Float64, 1}`: nominal longitude of h-points [degrees_E] +* `yh::Array{Float64, 1}`: nominal latitude of h-points [degrees_N] +* `zl::Array{Float64, 1}`: vertical position [m] +* `u::Array{Float64, Int}`: zonal velocity (positive towards west) [m/s], + dimensions correspond to placement in `[xq, yq, zl, time]`. +* `v::Array{Float64, Int}`: meridional velocity (positive towards north) [m/s], + dimensions correspond to placement in `[xq, yq, zl, time]`. +* `ice_floe_list::Array{Float64, Int}`: interface height relative to mean sea + level [m], dimensions correspond to placement in `[xh, yh, zi, time]`. +=# +type Atmosphere + input_file::Any + + time::Array{Float64, 1} + + # q-point (cell corner) positions + xq::Array{Float64, 2} + yq::Array{Float64, 2} + + # h-point (cell center) positions + xh::Array{Float64, 2} + yh::Array{Float64, 2} + + # Vertical positions + zl::Array{Float64, 1} + + # Field values + u::Array{Float64, 4} + v::Array{Float64, 4} + + ice_floe_list::Array{Array{Int, 1}, 2} +end + # Top-level simulation type type Simulation id::String @@ -200,4 +256,5 @@ type Simulation ice_floes::Array{IceFloeCylindrical, 1} ocean::Ocean + atmosphere::Atmosphere end diff --git a/src/grid.jl b/src/grid.jl @@ -32,21 +32,21 @@ function bilinearInterpolation(field::Array{Float64, 4}, end """ - curl(ocean, x_tilde, y_tilde, i, j, k, it) + curl(grid, 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 +* `grid::Any`: 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, +function curl(grid::Any, x_tilde::Float64, y_tilde::Float64, i::Int, @@ -54,22 +54,22 @@ function curl(ocean::Ocean, k::Int, it::Int) - sw, se, ne, nw = getCellCornerCoordinates(ocean, i, j) + sw, se, ne, nw = getCellCornerCoordinates(grid, 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)) + ((grid.v[i+1, j , k,it] - grid.v[i , j , k,it])/sw_se*(1. - y_tilde) + + ((grid.v[i+1, j+1, k,it] - grid.v[i , j+1, k,it])/nw_ne)*y_tilde) - + ((grid.u[i , j+1, k,it] - grid.u[i , j , k,it])/sw_nw*(1. - x_tilde) + + ((grid.u[i+1, j+1, k,it] - grid.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. +Find ice-floe positions in grid, based on their center positions. """ function sortIceFloesInOceanGrid!(simulation::Simulation; verbose=false) @@ -234,31 +234,31 @@ Returns ocean-grid corner coordinates in the following order (south-west corner, south-east corner, north-east corner, north-west corner). # Arguments -* `ocean::Ocean`: ocean object containing grid. +* `grid::Any`: grid object (Ocean or Atmosphere) containing grid. * `i::Int`: x-index of cell. * `j::Int`: y-index of cell. """ -function getCellCornerCoordinates(ocean::Ocean, i::Int, j::Int) - sw = [ocean.xq[ i, j], ocean.yq[ i, j]] - se = [ocean.xq[i+1, j], ocean.yq[i+1, j]] - ne = [ocean.xq[i+1, j+1], ocean.yq[i+1, j+1]] - nw = [ocean.xq[ i, j+1], ocean.yq[ i, j+1]] +function getCellCornerCoordinates(grid::Any, i::Int, j::Int) + sw = [grid.xq[ i, j], grid.yq[ i, j]] + se = [grid.xq[i+1, j], grid.yq[i+1, j]] + ne = [grid.xq[i+1, j+1], grid.yq[i+1, j+1]] + nw = [grid.xq[ i, j+1], grid.yq[ i, j+1]] return sw, se, ne, nw end export getCellCenterCoordinates """ - getCellCenterCoordinates(ocean, i, j) + getCellCenterCoordinates(grid, i, j) -Returns ocean-grid center coordinates (h-point). +Returns grid center coordinates (h-point). # Arguments -* `ocean::Ocean`: ocean object containing grid. +* `grid::Any`: grid object containing grid. * `i::Int`: x-index of cell. * `j::Int`: y-index of cell. """ -function getCellCenterCoordinates(ocean::Ocean, i::Int, j::Int) - return [ocean.xh[i, j], ocean.yh[i, j]] +function getCellCenterCoordinates(grid::Any, i::Int, j::Int) + return [grid.xh[i, j], grid.yh[i, j]] end export areaOfTriangle diff --git a/src/icefloe.jl b/src/icefloe.jl @@ -37,14 +37,17 @@ function addIceFloeCylindrical(simulation::Simulation, # Hopkins 2004 ocean_drag_coeff_vert::float = 0.85, # H&C 2011 ocean_drag_coeff_horiz::float = 5e-4, # H&C 2011 - atmos_drag_coeff_vert::float = 0.4, # H&C 2011 - atmos_drag_coeff_horiz::float = 2.5e-4, # H&C2011 + atmosphere_drag_coeff_vert::float = 0.4, + # H&C 2011 + atmosphere_drag_coeff_horiz::float = 2.5e-4, + # H&C2011 pressure::float = 0., fixed::Bool = false, rotating::Bool = true, enabled::Bool = true, verbose::Bool = true, ocean_grid_pos::Array{Int, 1} = [0, 0], + atmosphere_grid_pos::Array{Int, 1} = [0, 0], n_contacts::Int = 0, contacts::Array{Int, 1} = zeros(Int, Nc_max), contact_parallel_displacement:: @@ -123,12 +126,13 @@ function addIceFloeCylindrical(simulation::Simulation, ocean_drag_coeff_vert, ocean_drag_coeff_horiz, - atmos_drag_coeff_vert, - atmos_drag_coeff_horiz, + atmosphere_drag_coeff_vert, + atmosphere_drag_coeff_horiz, pressure, n_contacts, ocean_grid_pos, + atmosphere_grid_pos, contacts, contact_parallel_displacement, contact_age @@ -289,10 +293,10 @@ function convertIceFloeDataToArrays(simulation::Simulation) simulation.ice_floes[i].ocean_drag_coeff_vert ifarr.ocean_drag_coeff_horiz[i] = simulation.ice_floes[i].ocean_drag_coeff_horiz - ifarr.atmos_drag_coeff_vert[i] = - simulation.ice_floes[i].atmos_drag_coeff_vert - ifarr.atmos_drag_coeff_horiz[i] = - simulation.ice_floes[i].atmos_drag_coeff_horiz + ifarr.atmosphere_drag_coeff_vert[i] = + simulation.ice_floes[i].atmosphere_drag_coeff_vert + ifarr.atmosphere_drag_coeff_horiz[i] = + simulation.ice_floes[i].atmosphere_drag_coeff_horiz ifarr.pressure[i] = simulation.ice_floes[i].pressure @@ -348,8 +352,8 @@ function printIceFloeInfo(f::IceFloeCylindrical) println(" c_o_v: $(f.ocean_drag_coeff_vert)") println(" c_o_h: $(f.ocean_drag_coeff_horiz)") - println(" c_a_v: $(f.atmos_drag_coeff_vert)") - println(" c_a_h: $(f.atmos_drag_coeff_horiz)\n") + println(" c_a_v: $(f.atmosphere_drag_coeff_vert)") + println(" c_a_h: $(f.atmosphere_drag_coeff_horiz)\n") println(" pressure: $(f.pressure) Pa") println(" n_contacts: $(f.n_contacts)") diff --git a/src/io.jl b/src/io.jl @@ -11,12 +11,13 @@ can be visualized by applying a *Glyph* filter. If the simulation contains an `Ocean` data structure, it's contents will be written to separate `.vtu` files. This can be disabled by setting the argument -`ocean=false`. +`ocean=false`. The same is true for the atmosphere. """ function writeVTK(simulation::Simulation; folder::String=".", verbose::Bool=true, - ocean::Bool=true) + ocean::Bool=true, + atmosphere::Bool=true) simulation.file_number += 1 filename = string(folder, "/", simulation.id, ".icefloes.", @@ -32,6 +33,12 @@ function writeVTK(simulation::Simulation; simulation.file_number) writeOceanVTK(simulation.ocean, filename, verbose=verbose) end + + if typeof(simulation.atmosphere.input_file) != Bool && atmosphere + filename = string(folder, "/", simulation.id, ".atmosphere.", + simulation.file_number) + writeOceanVTK(simulation.atmosphere, filename, verbose=verbose) + end end export writeIceFloeVTK @@ -110,9 +117,9 @@ function writeIceFloeVTK(simulation::Simulation, "Ocean drag coefficient (vertical) [-]") WriteVTK.vtk_point_data(vtkfile, ifarr.ocean_drag_coeff_horiz, "Ocean drag coefficient (horizontal) [-]") - WriteVTK.vtk_point_data(vtkfile, ifarr.atmos_drag_coeff_vert, + WriteVTK.vtk_point_data(vtkfile, ifarr.atmosphere_drag_coeff_vert, "Atmosphere drag coefficient (vertical) [-]") - WriteVTK.vtk_point_data(vtkfile, ifarr.atmos_drag_coeff_horiz, + WriteVTK.vtk_point_data(vtkfile, ifarr.atmosphere_drag_coeff_horiz, "Atmosphere drag coefficient (horizontal) [-]") WriteVTK.vtk_point_data(vtkfile, ifarr.pressure, @@ -422,6 +429,60 @@ function writeOceanVTK(ocean::Ocean, end end +export writeAtmosphereVTK +""" +Write a VTK file to disk containing all atmosphere data in the `simulation` in a +structured grid (file type `.vts`). These files can be read by ParaView and can +be visualized by applying a *Glyph* filter. This function is called by +`writeVTK()`. +""" +function writeAtmosphereVTK(atmosphere::Atmosphere, + filename::String; + verbose::Bool=false) + + # make each coordinate array three-dimensional + xq = similar(atmosphere.u[:,:,:,1]) + yq = similar(atmosphere.u[:,:,:,1]) + zq = similar(atmosphere.u[:,:,:,1]) + + for iz=1:size(xq, 3) + xq[:,:,iz] = atmosphere.xq + yq[:,:,iz] = atmosphere.yq + end + for ix=1:size(xq, 1) + for iy=1:size(xq, 2) + zq[ix,iy,:] = atmosphere.zl + end + end + + # add arrays to VTK file + vtkfile = WriteVTK.vtk_grid(filename, xq, yq, zq) + + WriteVTK.vtk_point_data(vtkfile, atmosphere.u[:, :, :, 1], + "u: Zonal velocity [m/s]") + WriteVTK.vtk_point_data(vtkfile, atmosphere.v[:, :, :, 1], + "v: Meridional velocity [m/s]") + # write velocities as 3d vector + vel = zeros(3, size(xq, 1), size(xq, 2), size(xq, 3)) + for ix=1:size(xq, 1) + for iy=1:size(xq, 2) + for iz=1:size(xq, 3) + vel[1, ix, iy, iz] = atmosphere.u[ix, iy, iz, 1] + vel[2, ix, iy, iz] = atmosphere.v[ix, iy, iz, 1] + end + end + end + + WriteVTK.vtk_point_data(vtkfile, vel, "Velocity vector [m/s]") + + outfiles = WriteVTK.vtk_save(vtkfile) + if verbose + info("Output file: " * outfiles[1]) + else + return nothing + end +end + export removeSimulationFiles """ removeSimulationFiles(simulation[, folder]) diff --git a/src/simulation.jl b/src/simulation.jl @@ -9,7 +9,9 @@ export createSimulation time_step::Float64=-1., file_time_step::Float64=-1., file_number::Int=0, - ice_floes=Array{IceFloeCylindrical, 1}[]) + ice_floes=Array{IceFloeCylindrical, 1}[], + ocean::Ocean, + atmosphere::Atmosphere) Create a simulation object containing all relevant variables such as temporal parameters, and lists of ice floes and contacts. @@ -26,7 +28,8 @@ function createSimulation(;id::String="unnamed", file_number::Int=0, file_time_since_output_file::Float64=0., ice_floes=Array{IceFloeCylindrical, 1}[], - ocean::Ocean=createEmptyOcean()) + ocean::Ocean=createEmptyOcean(), + atmosphere::Atmosphere=createEmptyAtmosphere()) return Simulation(id, time_iteration, @@ -37,7 +40,8 @@ function createSimulation(;id::String="unnamed", file_number, file_time_since_output_file, ice_floes, - ocean) + ocean, + atmosphere) end export run!