2020-04-09 21:13:38 +02:00
import numpy as np
import scipy . ndimage as im
2020-11-14 16:10:32 +01:00
from . rivermapper import flow
2020-04-09 21:13:38 +02:00
def advection ( dem , dirs , rivers , time , K = 1 , m = 0.5 , sea_level = 0 ) :
2020-04-26 17:13:38 +02:00
"""
Simulate erosion by rivers .
This models erosion as an upstream advection of elevations ( " erosion waves " ) .
Advection speed depends on water flux and parameters :
v = K * flux ^ m
"""
2020-04-09 21:13:38 +02:00
dirs = dirs . copy ( )
dirs [ 0 , : ] = 0
dirs [ - 1 , : ] = 0
dirs [ : , 0 ] = 0
dirs [ : , - 1 ] = 0
2020-04-26 17:13:38 +02:00
adv_time = 1 / ( K * rivers * * m ) # For every pixel, calculate the time an "erosion wave" will need to cross it.
2020-04-09 21:13:38 +02:00
dem = np . maximum ( dem , sea_level )
dem_new = np . zeros ( dem . shape )
for y in range ( dirs . shape [ 0 ] ) :
for x in range ( dirs . shape [ 1 ] ) :
2020-04-26 17:13:38 +02:00
# Elevations propagate upstream, so for every pixel we seek the downstream pixel whose erosion wave just reached the current pixel.
# This means summing the advection times downstream until we reach the erosion time.
2020-04-09 21:13:38 +02:00
x0 , y0 = x , y
x1 , y1 = x , y
remaining = time
while True :
2020-04-26 17:13:38 +02:00
# Move one pixel downstream
2020-04-09 21:13:38 +02:00
flow_dir = dirs [ y0 , x0 ]
if flow_dir == 0 :
remaining = 0
break
elif flow_dir == 1 :
y1 + = 1
elif flow_dir == 2 :
x1 + = 1
elif flow_dir == 3 :
y1 - = 1
elif flow_dir == 4 :
x1 - = 1
2020-04-26 17:13:38 +02:00
if remaining < = adv_time [ y0 , x0 ] : # Time is over, we found it.
2020-04-09 21:13:38 +02:00
break
remaining - = adv_time [ y0 , x0 ]
x0 , y0 = x1 , y1
c = remaining / adv_time [ y0 , x0 ]
2020-04-26 17:13:38 +02:00
dem_new [ y , x ] = c * dem [ y1 , x1 ] + ( 1 - c ) * dem [ y0 , x0 ] # If between 2 pixels, perform linear interpolation.
2020-04-09 21:13:38 +02:00
return np . minimum ( dem , dem_new )
def diffusion ( dem , time , d = 1 ) :
radius = d * time * * .5
2020-04-26 17:13:38 +02:00
return im . gaussian_filter ( dem , radius , mode = ' reflect ' ) # Diffusive erosion is a simple Gaussian blur
2020-04-09 21:13:38 +02:00
class EvolutionModel :
2020-04-10 19:37:27 +02:00
def __init__ ( self , dem , K = 1 , m = 0.5 , d = 1 , sea_level = 0 , flow = False , flex_radius = 100 ) :
2020-04-09 21:13:38 +02:00
self . dem = dem
#self.bedrock = dem
self . K = K
self . m = m
self . d = d
self . sea_level = sea_level
2020-04-10 19:37:27 +02:00
self . flex_radius = flex_radius
self . define_isostasy ( )
2020-04-09 21:13:38 +02:00
if flow :
self . calculate_flow ( )
else :
self . lakes = dem
self . dirs = np . zeros ( dem . shape , dtype = ' u1 ' )
self . rivers = np . zeros ( dem . shape , dtype = ' u4 ' )
self . flow_uptodate = False
def calculate_flow ( self ) :
2020-11-14 16:10:32 +01:00
self . dirs , self . lakes , self . rivers = flow ( self . dem )
2020-04-09 21:13:38 +02:00
self . flow_uptodate = True
def advection ( self , time ) :
dem = advection ( self . lakes , self . dirs , self . rivers , time , K = self . K , m = self . m , sea_level = self . sea_level )
self . dem = np . minimum ( dem , self . dem )
self . flow_uptodate = False
def diffusion ( self , time ) :
self . dem = diffusion ( self . dem , time , d = self . d )
self . flow_uptodate = False
2020-04-10 19:37:27 +02:00
def define_isostasy ( self ) :
2020-04-26 17:13:38 +02:00
self . ref_isostasy = im . gaussian_filter ( self . dem , self . flex_radius , mode = ' reflect ' ) # Define a blurred version of the DEM that will be considered as the reference isostatic elevation.
2020-04-10 19:37:27 +02:00
def adjust_isostasy ( self , rate = 1 ) :
2020-04-26 17:13:38 +02:00
isostasy = im . gaussian_filter ( self . dem , self . flex_radius , mode = ' reflect ' ) # Calculate blurred DEM
correction = ( self . ref_isostasy - isostasy ) * rate # Compare it with the reference isostasy
self . dem = self . dem + correction # Adjust