Skip to content

Commit

Permalink
Update README (#103)
Browse files Browse the repository at this point in the history
* Redo README text and make new files for other documentation sections

* Update readme to make it nicer

* Create title simulation

* Change title video to gif

* Add title gif

* Remove spacing in readme
  • Loading branch information
skygering authored Aug 7, 2024
1 parent 940ecdf commit 3aa0296
Show file tree
Hide file tree
Showing 7 changed files with 214 additions and 135 deletions.
170 changes: 36 additions & 134 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@

<!-- description -->
<p align="center">
<strong> Sea-ice model to explicitly simulate individual floe life cycles using complex discrete elements with time-evolving shapes. Easy to couple with Oceananigans for explorations of coupled ice-ocean dynamics. Ported from MATLAB to Julia.</strong>
<strong> Fast and Flexible Sea Ice Dynamics </strong>
</p>

<!-- Information badges -->
<!-- Repo badges -->
<p align="center">
<a href="https://caltech-octo.github.io/Subzero.jl/dev/">
<img alt="Docs latest" src="https://img.shields.io/badge/docs-latest-blue.svg" />
</a>
<a href="https://www.repostatus.org/#active">
<img alt="Repo status" src="https://www.repostatus.org/badges/latest/active.svg?style=flat-square" />
</a>
</p>

<!-- CI/CD badges -->
<p align="center">
<a href="https://github.com/Caltech-OCTO/Subzero.jl/actions/workflows/CI.yml?query=branch%3Amain">
<img alt="GitHub Actions CI Status" src="https://github.com/Caltech-OCTO/Subzero.jl/actions/workflows/CI.yml/badge.svg?branch=main">
</a>
Expand All @@ -25,149 +24,52 @@
</a>
</p>

Subzero.jl is a native [Julia](https://julialang.org/) discrete-element model (DEM) for exploring fine-scale sea ice dynamics,
reimplementing MATLAB model [SubZero by Manucharyan and Montemuro](https://doi.org/10.1029/2022MS003247).

Subzero is an easy-to-use Julia translation of Manucharyan and Montemuro’s model described in the paper “SubZero: A Sea Ice Model With an Explicit Representation of the Floe Life Cycle.” The model has been restructured to leverage Julia’s language abstractions for ease of setting up new simulation runs and allowing more types of simulations without code modifications. It has been designed for stand-alone simulations, or to be coupled per-timestep with ocean model Oceananigans.
Subzero.jl is **fast** and **flexible**.

Subzero.jl was ported and restructured by Skylar Gering and originally developed by Georgy Manucharyan and Brandon Montemuro.
- 🚀 Runs over **35 times faster** that original MATLAB model for title simulation!
- 🧩 Modular simulation model makes it easy to customize simulations within a **single_ run file**!
- Enable and disable physical processes such as fracturing, ridging, and welding
- Choose algorithms for key processes (or add your own!)

## Contents
## Documentation

* [Installation instructions](#installation-instructions)
* [Running your first model](#running-your-first-model)
* [Citing](#citing)
* [Contributing](#contributing)
* [Movies](#movies)
* [Performance benchmarks](#performance-benchmarks)
To learn how to build and run simulations, [check out our documentation and tutorials](https://caltech-octo.github.io/Subzero.jl/dev/)!

## Installation Instructions:
## Installation

Subzero is not yet a publically registered Julia package. If you have access to this repository, you have ability to use it as a package added directly from GitHub. This will require having a SSH key on your computer and stored in GitHub so that you are able to securely use this code as it is in private repository for now.
Subzero is a [registered Julia package](https://julialang.org/packages/). So to install it,

You can create and add a SSH key using the following instructions from GitHub:
1. [Checking for existing SSH keys](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/checking-for-existing-ssh-keys)
2. [Generating a new SSH key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent)
3. [Adding SSH key to your GitHub account](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account)
4. [Checking your SSH connection](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/testing-your-ssh-connection)
1. [Download Julia](https://julialang.org/downloads/) (version 1.9 or later).

Once you have established your SSH connection from within terminal, you now need to update your Julia `startup.jl` file. This is within the `.julia/config` folder. If you don't have a `.config` folder, please make one using `mkdir config` run on terminal within your `.julia` folder. If you don't have a `startup.jl` file you can make this using `touch startup.jl` within the `config` folder. Then, using a text editor (such as vim), add the following line to your `startup.jl` file:
2. Launch Julia and type

`ENV["JULIA_PKG_USE_CLI_GIT"]=true`
```julia
julia> using Pkg

We need this as Julia's SSH library can't read the types of SSH keys that GitHub now requires. This will have Julia use your local command line interface (CLI) version of Git. This only works with Julia 1.7 and higher.
julia> Pkg.add("Subzero")
```

At this point, you can start a Julia REPL and enter into the package manager mode. In package manager mode, you can simply give the command
## Citing

`add "git@github.com:Caltech-OCTO/Subzero.jl.git"`
If you use Subzero.jl as part of your research, teaching, or other activities, we would be grateful if you could cite our work.
We are currently working on a JOSS paper, which will be linked here. If you are ready to publish before that, please reach out to us to discuss citations.

which will add Subzero as a package.
## Contributing

## Running your first model:
If you’re interested in contributing to the development Subzero, we would love to have you!
If you have found a bug or have a new feature that you want to help implement, please open an issue on the repository. **We can't wait to talk to you.

For detailed instructions on how to create different types of models and simulations, please see the [documentation.md file](https://github.com/Caltech-OCTO/Subzero.jl/blob/main/documentation.md). However, we will give a basic example here.
Please also check out [our contributers' guide](https://caltech-octo.github.io/Subzero.jl/dev/contribute/).

Let’s run a basic simulation with initially stationary floes pushed into a collision boundary by a uniform, zonally flowing ocean. In this simulation, collisions between floes are on by default and we will enable floe fracturing.
## Authors

```julia
# Create environment
grid = RegRectilinearGrid(
(0, 1e5), # xbounds
(0, 1e5), # ybounds
1e4, # grid cell width
1e4, # grid cell height
)
ocean = Ocean(grid, 0.25, 0.0, 0.0) # 0.25m/s u-velocity, 0m/s v-velocity, 0C temperature in all grid cells
atmos = Atmos(grid, 0.0, 0.1, -1.0) # 0m/s u-velocity, 0.1m/s v-velocity, -1C temperature in all grid cells
# Create domain
domain = Domain(
CollisionBoundary(North, grid),
CollisionBoundary(South, grid),
CollisionBoundary(East, grid),
CollisionBoundary(West, grid),
)
# Create floes
floe_settings = FloeSettings(stress_calculator = DecayAreaScaledCalculator(), min_floe_area = 1e5)
floe_arr = initialize_floe_field(
Float64,
100, # number of floes
[0.7], # floe concentration
domain,
0.5, # average floe height
0.05; # floe height variability
floe_settings = floe_settings,
)
# Create model
model = Model(grid, ocean, atmos, domain, floe_arr)

# Create settings
modulus = 1.5e3*(mean(sqrt.(floe_arr.area)) + minimum(sqrt.(floe_arr.area)))
consts = Constants(E = modulus)

fracture_settings = FractureSettings(
fractures_on = true,
criteria = HiblerYieldCurve(floe_arr),
Δt = 75,
npieces = 3,
deform_on = true,
)
# Create output writers
dir = "output/sim"
initwriter = InitialStateOutputWriter(
dir = dir,
filename = "initial_state.jld2",
overwrite = true,
)
floewriter = FloeOutputWriter(
100,
dir = dir,
filename = "floes.jld2",
overwrite = true,
)
writers = OutputWriters(initwriter, floewriter)
# Create simulation
Δt = 10
simulation = Simulation(
model = model,
consts = consts,
Δt = Δt, # 10 second timesteps
nΔt = 10000, # Run for 10000 timesteps
verbose = true;
fracture_settings = fracture_settings,
writers = writers,
)
# Run simulation
run!(simulation)

# Plot simulation
plot_sim(
"output/sim/floes.jld2",
"output/sim/initial_state.jld2",
Δt,
"output/sim/example.mp4",
)
```

Check out our [documentation](https://github.com/Caltech-OCTO/Subzero.jl/blob/main/documentation.md) for more examples and explanations for the code above.

## Citing:
We still need to figure this out. Please reach out so we can discuss.

## Contributing:
If you’re interested in helping develop Subzero, have found a bug, or have a new feature that you want implemented, please open an issue on the repository and we can talk about this. We will be working on a contributers' guide in the future.

## Movies:

**Shear Flow**
In this simulation, the ocean flow is 0m/s at the top and bottom of the domain, gradually increasing towards 0.5m/s in the middle of the domain. All four boundaries are periodic. We used a timestep of 20 seconds for 4,320 timesteps, which is one day.

<img src="https://github.com/Caltech-OCTO/Subzero.jl/assets/60117338/2b13746e-e4db-4ceb-92c5-59f50f2cab32" alt="Shear flow" width="800">

**Simple Strait**
In this simulation, the ocean floe is uniformly -0.3 m/s from top to bottom of the simulation. The top and bottom boundaries are periodic, with the right and left being collision boundaries. However, the collision boundaries are covered by two pieces of topography forming the strait. This simulation also has 20 second timesteps, run for 4,320 timesteps, which is one day.

<img src="https://github.com/Caltech-OCTO/Subzero.jl/assets/60117338/ec331900-aeb7-4b05-a713-a0d5a2b529b8" alt="Simple strait" width="800">

## Performance Benchmarks:
Here we compare Subzero runtimes in Julia and MATLAB for the shear flow simulation. The code was run on Caltech's HPC cluster. The Julia code was run with 12 threads (12 CPUs per 1 node and 1 task). The MATLAB code has parfor loops with 12 workers (12 tasks, 1 CPU per task).

<img src="https://github.com/Caltech-OCTO/Subzero.jl/assets/60117338/9532e883-0f1d-4399-b713-de24803de72f" alt="Performance data" width="800">
- Primary Author: [**Skylar Gering (@skygering)**](https://github.com/skygering)

The list of [Subzero contributors](https://github.com/Caltech-OCTO/Subzero.jl/graphs/contributors):

<a href="https://github.com/Caltech-OCTO/Subzero.jl/graphs/contributors">
<img src="https://contrib.rocks/image?repo=Caltech-OCTO/Subzero.jl" />
</a>
Binary file added docs/src/assets/title.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 97 additions & 0 deletions docs/src/assets/title.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
using Subzero, JLD2, CairoMakie, GeoInterfaceMakie, Random, Statistics

const FT = Float64
const Lx = 8e4
const Ly = 8e4
const Δgrid = 2e3
const hmean = 0.25
const Δh = 0.0
const Δt = 20
const nΔt = 5000

# Model instantiation
grid = RegRectilinearGrid((0.0, Lx), (0.0, Ly), Δgrid, Δgrid)

uvels = repeat(
[range(0, 0.2, length = 21); range(0.2, 0, length = 20)],
outer = (1, 41),
)
ocean = Ocean(
uvels',
zeros(grid.Nx + 1, grid.Ny + 1),
zeros(grid.Nx + 1, grid.Ny + 1),
)
atmos = Atmos(grid, 0.0, 0.0, -1.0)

# Domain creation
nboundary = PeriodicBoundary(North, grid)
sboundary = PeriodicBoundary(South, grid)
eboundary = PeriodicBoundary(East, grid)
wboundary = PeriodicBoundary(West, grid)
domain = Domain(nboundary, sboundary, eboundary, wboundary)

# Floe creation
floe_arr = initialize_floe_field(FT, 400, [0.85], domain, hmean, Δh; rng = Xoshiro(1))

# Model creation
model = Model(grid, ocean, atmos, domain, floe_arr)

# Simulation setup
modulus = 1.5e3*(mean(sqrt.(floe_arr.area)) + minimum(sqrt.(floe_arr.area)))
consts = Constants(E = modulus)

# Run simulation
dir = "output/title/"

# Output setup
floewriter = FloeOutputWriter(50, dir = dir, overwrite = true)
writers = OutputWriters(floewriter)

simulation = Simulation(; model, consts, Δt, nΔt, writers, verbose = true, rng = Xoshiro(1))
run!(simulation)

function plot_logo(floe_fn, Lx, Ly, dir)
# Floe Information
file = jldopen(floe_fn)
sim_polys = file["poly"]
timesteps = keys(sim_polys)

# Set up observables for recording (updated whenever `time[]` is set to a new value)
time = Observable(timesteps[1]) # note these are strings as we index into a JLD2 file
time_polys = @lift(sim_polys[$time])

# Set up figure
fig = Figure(; size = (1200, 300))

floe_rgb = (165, 222, 242)
floe_color = RGBf((floe_rgb ./ 255)...)
ocean_rgb = (4, 31, 74)
ocean_color = RGBf((ocean_rgb ./ 255)...)
text_outline_rgb = (219, 76, 0)
text_outline_color = RGBf((text_outline_rgb ./ 255)...)

ax = Axis(fig[1, 1]; limits = (0.0, Lx, 0.0, Ly), backgroundcolor = ocean_color)
hidedecorations!(ax)

# Plot starting state (floes + topography)
poly!(time_polys, color = floe_color, strokecolor = :black, strokewidth = 0.5) # floes
text!(
Lx/2, Ly/2;
align = (:center, :center),
text = "Subzero.jl",
font = :bold,
fontsize = 175,
strokecolor = text_outline_color,
strokewidth = 5,
)

# Create movie
record(fig, dir*"title.gif", timesteps; framerate = 20) do t
time[] = t # updating the time auto updates the related time_polys
end

# End movie and close file
close(file)
end

plot_logo(dir*"floes.jld2", Lx, Ly, dir)
Empty file added docs/src/contribute.md
Empty file.
2 changes: 2 additions & 0 deletions docs/src/introduction.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# Introduction

Sea-ice model to explicitly simulate individual floe life cycles using complex discrete elements with time-evolving shapes. Easy to couple with Oceananigans for explorations of coupled ice-ocean dynamics. Ported from MATLAB to Julia.

## Main concepts
78 changes: 78 additions & 0 deletions docs/src/tutorial.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Let’s run a basic simulation with initially stationary floes pushed into a collision boundary by a uniform, zonally flowing ocean. In this simulation, collisions between floes are on by default and we will enable floe fracturing.

# Create environment
grid = RegRectilinearGrid(
(0, 1e5), # xbounds
(0, 1e5), # ybounds
1e4, # grid cell width
1e4, # grid cell height
)
ocean = Ocean(grid, 0.25, 0.0, 0.0) # 0.25m/s u-velocity, 0m/s v-velocity, 0C temperature in all grid cells
atmos = Atmos(grid, 0.0, 0.1, -1.0) # 0m/s u-velocity, 0.1m/s v-velocity, -1C temperature in all grid cells
# Create domain
domain = Domain(
CollisionBoundary(North, grid),
CollisionBoundary(South, grid),
CollisionBoundary(East, grid),
CollisionBoundary(West, grid),
)
# Create floes
floe_settings = FloeSettings(stress_calculator = DecayAreaScaledCalculator(), min_floe_area = 1e5)
floe_arr = initialize_floe_field(
Float64,
100, # number of floes
[0.7], # floe concentration
domain,
0.5, # average floe height
0.05; # floe height variability
floe_settings = floe_settings,
)
# Create model
model = Model(grid, ocean, atmos, domain, floe_arr)

# Create settings
modulus = 1.5e3*(mean(sqrt.(floe_arr.area)) + minimum(sqrt.(floe_arr.area)))
consts = Constants(E = modulus)

fracture_settings = FractureSettings(
fractures_on = true,
criteria = HiblerYieldCurve(floe_arr),
Δt = 75,
npieces = 3,
deform_on = true,
)
# Create output writers
dir = "output/sim"
initwriter = InitialStateOutputWriter(
dir = dir,
filename = "initial_state.jld2",
overwrite = true,
)
floewriter = FloeOutputWriter(
100,
dir = dir,
filename = "floes.jld2",
overwrite = true,
)
writers = OutputWriters(initwriter, floewriter)
# Create simulation
Δt = 10
simulation = Simulation(
model = model,
consts = consts,
Δt = Δt, # 10 second timesteps
nΔt = 10000, # Run for 10000 timesteps
verbose = true;
fracture_settings = fracture_settings,
writers = writers,
)
# Run simulation
run!(simulation)

# Plot simulation
plot_sim(
"output/sim/floes.jld2",
"output/sim/initial_state.jld2",
Δt,
"output/sim/example.mp4",
)
2 changes: 1 addition & 1 deletion src/physical_processes/simplification.jl
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function dissolve_floe!(floe, grid::RegRectilinearGrid, domain, dissolved)
yidx = shift_cell_idx(yidx, grid.Ny + 1, domain.north)
# If centroid is within bounds after wrapping, add mass to dissolved
if 0 < xidx <= grid.Nx && 0 < yidx <= grid.Ny
dissolved[yidx, xidx] += floe.mass
dissolved[xidx, yidx] += floe.mass
end
return
end
Expand Down

0 comments on commit 3aa0296

Please sign in to comment.