Skip to content

Commit

Permalink
Merge pull request #121 from albert-de-montserrat/adm/volcano
Browse files Browse the repository at this point in the history
Adds volcano topography with corresponding temperature field
  • Loading branch information
albert-de-montserrat authored Jun 17, 2024
2 parents e0d90c4 + 68b4e88 commit 4b3886a
Show file tree
Hide file tree
Showing 5 changed files with 280 additions and 2 deletions.
3 changes: 2 additions & 1 deletion docs/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ makedocs(;
"19 - Jura tutorial" => "man/Tutorial_Jura.md",
"20 - 2D model setups" => "man/Tutorial_NumericalModel_2D.md",
"21 - 3D model setups" => "man/Tutorial_NumericalModel_3D.md",
"22 - Build geometry from polygons" => "man/tutorial_Polygon_structures.md"
"22 - 3D model setups" => "man/Tutorial_VolcanoModel_3D.md",
"23 - Build geometry from polygons" => "man/tutorial_Polygon_structures.md"
],
"User Guide" => Any[
"Installation" => "man/installation.md",
Expand Down
Binary file added docs/src/assets/img/VolcanoModel3D.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions docs/src/man/Tutorial_VolcanoModel_3D.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Simple model of a magmatic chamber with a volcano on top

### Aim
The aim of this tutorial is to show you how to create 3D numerical model setups that can be used as initial setups for other codes.

### Generating the model

Lets start with creating a 3D model setup in cartesian coordinates, which uses the `CartData` data structure, with a resolution of $ 128 \times 128 \times 128 $ grid points, inside the domain $\Omega \in [-100,100] \times [-100,100] \times [-110,50]$ km

```julia
using GeophysicalModelGenerator

nx,ny,nz = 128, 128, 128
x = range(-100, 100, nx);
y = range(-100, 100, ny);
z = range(-110, 50, nz);
Grid = CartData(xyz_grid(x,y,z));
```

Now we create an integer array that will hold the `Phases` information (which usually refers to the material or rock type in the simulation)

```julia
Phases = fill(0, nx, ny, nz);
```

And as in the previous tutorials we initialize the temperature field:
```julia
Temp = fill(1350.0, nx,ny,nz);
```

For simplicity, we will assume a model with thee horizontal layers with different rheology where later we add the volcano and the magmatic chamber. We use `add_box!` to generate the initial horizontally layered model:

```julia
lith = LithosphericPhases(Layers=[15 45 100], Phases=[1 2 3])
add_box!(Phases, Temp, Grid;
xlim=(-100, 100),
ylim=(-400, 400.0),
zlim=(-110.0, 0.0),
phase = lith,
T = HalfspaceCoolingTemp(Age=20)
)
```

Then we can add the volcanic shape using `add_volcano!` function. In this case the base of the volcano will be centered at $x_i = (0,0,0)$, with a height of 10 km and a 15 km radius:
```julia
add_volcano!(Phases, Temp, Grid;
volcanic_phase = 1,
center = (0, 0, 0),
height = 10,
radius = 15,
base = 0.0,
background = nothing,
T = HalfspaceCoolingTemp(Age=20)
)
```
We can also add a magmatic chamber located below the volcano
```julia
add_ellipsoid!(Phases, Temp, Grid;
cen = (0, 0, -40),
axes = (10, 10, 10),
phase = ConstantPhase(4),
)
```

where we prescribe a constant temperature of $T=1400^{\circ}C$
```julia
@. Temp[Phases == 4] = 1400
Grid = addfield(Grid, (;Phases, Temp))
```

Finally we setup the temperature of the air to $T^{\text{air}}=0^{\circ}C$
```julia
@. Temp[Phases == 0] = 0
```

```julia
write_paraview(Grid,"VolcanoModel3D");
```

And the resulting image looks like
![Mechanical3D_Tutorial_2](../assets/img/VolcanoModel3D.png)
132 changes: 131 additions & 1 deletion src/Setup_geometry.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Base: show
# These are routines that help to create input geometries, such as slabs with a given angle
#

export add_box!, add_sphere!, add_ellipsoid!, add_cylinder!, add_layer!, add_polygon!, add_slab!, add_stripes!,
export add_box!, add_sphere!, add_ellipsoid!, add_cylinder!, add_layer!, add_polygon!, add_slab!, add_stripes!, add_volcano!,
make_volc_topo,
ConstantTemp, LinearTemp, HalfspaceCoolingTemp, SpreadingRateTemp, LithosphericTemp, LinearWeightedTemperature,
McKenzie_subducting_slab,
Expand Down Expand Up @@ -685,7 +685,82 @@ function Rot3D(X::_T,Y::_T,Z::_T, cosStrikeAngle::_T, sindStrikeAngle::_T, cosDi
return CoordRot[1], CoordRot[2], CoordRot[3]
end

"""
add_volcano!(
Phases, Temp, Grid::CartData;
volcanic_phase,
center,
height,
radius,
crater,
base,
background,
T,
)
Adds a volcano topography (cones and truncated cones)
Parameters
====
- Phases - Phase array (consistent with Grid)
- Temp - Temperature array (consistent with Grid)
- Grid - CartData
Optional Parameters
====
- volcanic_phase - phase number of the volcano,
- center - x- and -coordinates of center of volcano
- height - height of volcano
- radius - radius of volcano
- T - temperature structure of the volcano
- crater - this will create a truncated cone and the option defines the radius of the flat top
- base - this sets the flat topography around the volcano
- background - this allows loading in a topography and only adding the volcano on top (also allows stacking of several cones to get a volcano with different slopes)
"""
function add_volcano!(
Phases,
Temp,
Grid::CartData;
volcanic_phase = 1,
center = (0,0,0),
height = 0.0,
radius = 0.0,
crater = 0.0,
base = 0.0,
background = nothing,
T = HalfspaceCoolingTemp(Age=0)
)
H = make_volc_topo(Grid;
center = center,
height = height,
radius = radius,
crater = crater,
base = base,
background = background
)

ni = size(Grid.x)
ind = fill(false, ni...)
depth = similar(Grid.z.val)

for k in axes(ind, 3)
for j in axes(ind, 2), i in axes(ind, 1)
depth[i, j, k] = max(H[i, j] - Grid.z.val[i, j, k], 0)

if Grid.z.val[i, j, k] < H[i, j] && Grid.z.val[i, j, k] base
Phases[i, j, k] = volcanic_phase
end
if Phases[i, j, k] > 0
ind[i, j, k] = true
end
end
end

# @views Temp[ind .== false] .= 0.0
@views Temp[ind] .= compute_thermal_structure(Temp[ind], Grid.x.val[ind], Grid.y.val[ind], depth[ind], Phases[ind], T)

return nothing
end

"""
make_volc_topo(Grid::LaMEM_grid; center::Array{Float64, 1}, height::Float64, radius::Float64, crater::Float64,
Expand Down Expand Up @@ -797,6 +872,61 @@ function make_volc_topo(Grid::LaMEM_grid;
return CartData(reshape(X,nx,ny,1), reshape(Y,nx,ny,1), reshape(Topo,nx,ny,1), (Topography=reshape(Topo,nx,ny,1),))
end

function make_volc_topo(Grid::CartData;
center = (0,0,0),
height = 0.0,
radius = 0.0,
crater = 0.0,
base = 0.0,
background = nothing
)
# get node grid
X = @views Grid.x.val[:,:,1]
Y = @views Grid.y.val[:,:,1]
nx = size(X, 1)
ny = size(X, 2)
pos = similar(X)

for i in eachindex(pos)
# compute radial distance to volcano center
DX = X[i] - center[1]
DY = Y[i] - center[2]
RD = (DX^2 + DY^2)

# get radial distance from crater rim
RD -= crater

# find position relative to crater rim
dr = radius - crater
pos[i] = -RD / dr + 1
end

## assign topography
H = zeros(nx,ny)
# check if there is a background supplied
if background === nothing
H .= base
else
# background = nondimensionalize(background, CharUnits)
if size(background) == size(X)
H .= background
elseif size(background) == size(reshape(X,nx,ny,1))
H .= @views background[:,:,1]
else
error("Size of background must be ", nx, "x", ny)
end
end

for i in eachindex(pos)
if 0 pos[i] < 1
H[i] = pos[i] * (height - base) + base
elseif pos[i] 1
H[i] = height
end
end

return H
end

abstract type AbstractThermalStructure end

Expand Down
66 changes: 66 additions & 0 deletions volcano.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using GeophysicalModelGenerator

nx,ny,nz = 128, 128, 128
x = range(-100, 100, nx);
y = range(-100, 100, ny);
z = range(-110, 50, nz);
Grid = CartData(xyz_grid(x,y,z));

# Now we create an integer array that will hold the `Phases` information (which usually refers to the material or rock type in the simulation)
Phases = fill(0, nx, ny, nz);

# In many (geodynamic) models, one also has to define the temperature, so lets define it as well
Temp = fill(1350.0, nx, ny, nz);

lith = LithosphericPhases(Layers=[15 45 100], Phases=[1 2 3])

# And an an inclined part:
add_box!(Phases, Temp, Grid;
xlim=(-100, 100),
ylim=(-400, 400.0),
zlim=(-110.0, 0.0),
phase = lith,
Origin = (0,0,0),
T = HalfspaceCoolingTemp(Age=20));


# # Add them to the `CartData` dataset:
Grid = addfield(Grid,(;Phases, Temp))
# heatmap(x, z, Grid.fields.Temp[:,64,:])

# Which looks like
# write_paraview(Grid,"Grid3D_FreeSubduction");

center = (0, 0, 0)
height = 10 # [kmm]
radius = 15 # [km]
crater = 0.0
base = 0.0
background = nothing


add_volcano!(Phases, Temp, Grid;
volcanic_phase = 1,
center = (0, 0, 0),
height = 10,
radius = 15,
crater = 0.0,
base = 0.0,
background = nothing,
T = HalfspaceCoolingTemp(Age=20)
)

Grid = addfield(Grid,(;Phases, Temp))

write_paraview(Grid,"Grid3D_FreeSubduction");

Grid.fields.Temp[Grid.fields.Temp.==0] .= NaN
heatmap(x, z, Grid.fields.Temp[:,64,:])
heatmap(x, z, Grid.fields.Phases[:,64,:])

# heatmap(x, z, Grid.z.val[:,64,:])
# heatmap(x, z, depth[:,64,:])
# heatmap(x, z, ind[:,64,:])

# Grid.fields.Temp[:,:,1]
# lines(Grid.fields.Temp[64,64,:], depth[64,64,:])

0 comments on commit 4b3886a

Please sign in to comment.