|
6 | 6 | "source": [ |
7 | 7 | "# Introduction to the RockBlock and LayeredRockBlock objects\n", |
8 | 8 | "\n", |
9 | | - "The RockBlock and LayeredRockBlock are two landlab objects meant to make it easier to work with spatially variable lithology that produces spatially variable parameter values (e.g. stream power erodability and diffusivity). \n", |
| 9 | + "The RockBlock and LayeredRockBlock are two landlab objects meant to make it easier to work with spatially variable lithology that produces spatially variable parameter values (e.g. stream power erodability or diffusivity). \n", |
10 | 10 | "\n", |
11 | 11 | "In this tutorial we will first use the LayeredRockBlock to erode either dipping layeres or an anticline. Then we will use RockBlock to create inverted topography. \n", |
12 | 12 | "\n", |
13 | | - "To start, we will import the necessary modules. A note: this tutorial uses the [HoloViews package](http://holoviews.org) for visualization. This package is a great tool for dealing with multidimentional annotated data (e.g. an xarray dataset). If you get an error on import, consider updating dask (this is what the author needed to do in April 2018). " |
| 13 | + "To start, we will import the necessary modules. A note: this tutorial uses the [HoloViews package](http://holoviews.org) for visualization. This package is a great tool for dealing with multidimentional annotated data (e.g. an xarray dataset). If you get an error on import, consider updating dask (this is what the author needed to do in April 2018). You will also need to have the [Bokeh](https://bokeh.pydata.org/en/latest/) and [Matplotlib](https://matplotlib.org) packages installed." |
14 | 14 | ] |
15 | 15 | }, |
16 | 16 | { |
|
30 | 30 | "\n", |
31 | 31 | "from landlab import RasterModelGrid\n", |
32 | 32 | "from landlab.layers import RockBlock, LayeredRockBlock\n", |
33 | | - "from landlab.components import FlowAccumulator, FastscapeEroder\n", |
| 33 | + "from landlab.components import FlowAccumulator, FastscapeEroder, LinearDiffuser\n", |
34 | 34 | "from landlab.plot import imshow_grid" |
35 | 35 | ] |
36 | 36 | }, |
|
64 | 64 | "attrs = {'K_sp': {0: 0.0003,\n", |
65 | 65 | " 1: 0.0001}}\n", |
66 | 66 | "\n", |
67 | | - "mg = RasterModelGrid((50, 50), 100)\n", |
| 67 | + "mg = RasterModelGrid((100, 100), 200)\n", |
68 | 68 | "z = mg.add_zeros('node', 'topographic__elevation') \n", |
69 | 69 | "random_field = 0.01*np.random.randn(mg.size('node'))\n", |
70 | 70 | "z += random_field - random_field.min()\n", |
|
74 | 74 | "ids = np.tile([0,1], 20) \n", |
75 | 75 | "\n", |
76 | 76 | "# Anticline\n", |
77 | | - "rb = LayeredRockBlock(mg, z0s, ids, x0=2500, y0=2500, function = lambda x, y : ((0.005*x)**2+(0.005*y)**2), attrs=attrs)\n", |
| 77 | + "rb = LayeredRockBlock(mg, z0s, ids, x0=10000, y0=10000, function = lambda x, y : ((0.0015*x)**2+(0.0007*y)**2), attrs=attrs)\n", |
78 | 78 | "\n", |
79 | 79 | "# Shallow dips\n", |
80 | 80 | "#rb = LayeredRockBlock(mg, z0s, ids, x0=5000, y0=5000, function = lambda x, y : ((0.001*x)+(0.003*y)), attrs=attrs)\n", |
|
117 | 117 | { |
118 | 118 | "cell_type": "code", |
119 | 119 | "execution_count": null, |
120 | | - "metadata": { |
121 | | - "collapsed": true |
122 | | - }, |
| 120 | + "metadata": {}, |
123 | 121 | "outputs": [], |
124 | 122 | "source": [ |
125 | | - "nts = 400\n", |
| 123 | + "nts = 500\n", |
126 | 124 | "U = 0.001\n", |
127 | 125 | "dt = 1000\n", |
128 | 126 | "\n", |
129 | 127 | "fa = FlowAccumulator(mg)\n", |
130 | 128 | "sp = FastscapeEroder(mg, K_sp='K_sp')\n", |
131 | 129 | "\n", |
132 | 130 | "out_fields = ['topographic__elevation',\n", |
133 | | - " 'K_sp', \n", |
134 | 131 | " 'rock_type__id']\n", |
135 | 132 | "\n", |
136 | | - "ds = xr.Dataset(data_vars={'topographic__elevation' : (('y', 'x', 't'), np.empty((mg.shape[0], mg.shape[1], nts))),\n", |
137 | | - " 'K_sp' : (('y', 'x', 't'), np.empty((mg.shape[0], mg.shape[1], nts))),\n", |
138 | | - " 'rock_type__id': (('y', 'x', 't'), np.empty((mg.shape[0], mg.shape[1], nts)))},\n", |
| 133 | + "ds = xr.Dataset(data_vars={'topographic__elevation' : (('t', 'y', 'x'), np.empty((nts, mg.shape[0], mg.shape[1]))),\n", |
| 134 | + " 'rock_type__id': (('t', 'y', 'x'), np.empty((nts, mg.shape[0], mg.shape[1])))},\n", |
139 | 135 | " coords={'x': mg.x_of_node.reshape(mg.shape)[0,:],\n", |
140 | 136 | " 'y': mg.y_of_node.reshape(mg.shape)[:, 1],\n", |
141 | 137 | " 't': dt*np.arange(nts)/1e6})" |
|
147 | 143 | "source": [ |
148 | 144 | "Here we run the model. In each time step we first run the FlowAccumulator to direct flow and accumulatate drainage area. Then the FastscapeEroder erodes the topography based on the stream power equation using the erodability value in the field`'K_sp'`. We create an uplift field that uplifts only the model grid's core nodes. After uplifting these core nodes, we update the LayeredRockBlock. Importantly, we must tell the LayeredRockBlock how it has been advected upward by uplift. \n", |
149 | 145 | "\n", |
| 146 | + "`rb.run_one_step` has an optional argument `rock_id` to use when some material may be deposited. Since we are using the FastscapeEroder which is fully detachment limited, we don't need to set this. \n", |
| 147 | + "\n", |
150 | 148 | "Within each timestep we save information about the model for plotting. " |
151 | 149 | ] |
152 | 150 | }, |
|
167 | 165 | " rb.run_one_step(dz_advection = dz_ad)\n", |
168 | 166 | " \n", |
169 | 167 | " for of in out_fields:\n", |
170 | | - " ds[of][:,:,i] = mg['node'][of].reshape(mg.shape)\n" |
| 168 | + " ds[of][i,:,:] = mg['node'][of].reshape(mg.shape)" |
171 | 169 | ] |
172 | 170 | }, |
173 | 171 | { |
|
211 | 209 | "cell_type": "markdown", |
212 | 210 | "metadata": {}, |
213 | 211 | "source": [ |
214 | | - "Next we specify that we want two images, one showing rock type and one showing topographic elevation. A slider bar " |
| 212 | + "Next we specify that we want two images, one showing rock type and one showing topographic elevation. A slider bar shows us model time in millions of years. " |
215 | 213 | ] |
216 | 214 | }, |
217 | 215 | { |
218 | 216 | "cell_type": "code", |
219 | 217 | "execution_count": null, |
220 | | - "metadata": { |
221 | | - "collapsed": true |
222 | | - }, |
| 218 | + "metadata": {}, |
223 | 219 | "outputs": [], |
224 | 220 | "source": [ |
225 | 221 | "%opts Image (cmap='viridis')\n", |
226 | | - "\n", |
227 | 222 | "topo = hvds.to(hv.Image, ['x', 'y'], ['topographic__elevation'])\n", |
228 | 223 | "rock = hvds.to(hv.Image, ['x', 'y'], ['rock_type__id'])\n", |
229 | 224 | "\n", |
|
236 | 231 | "collapsed": true |
237 | 232 | }, |
238 | 233 | "source": [ |
239 | | - "Make inverted topography by filling RockBlock in with resistant material only where the DA is large. " |
| 234 | + "We can see the form of the anticline advecting through the topography. Cool!\n", |
| 235 | + "\n", |
| 236 | + "\n", |
| 237 | + "## Part 2 Creation of Inverted Topography\n", |
| 238 | + "\n", |
| 239 | + "Here we will explore making inverted topography by eroding a RockBlock with constant properties for half of the model evaluation time, and then filling RockBlock in with resistant material only where the drainage area is large. This is meant as a simple example of filling in valleys with volcanic material. \n", |
| 240 | + "\n", |
| 241 | + "All of the details of the options for creating a [RockBlock](http://landlab.readthedocs.io/en/release/landlab.layers.rockblock.html) can be found here. \n", |
| 242 | + "\n", |
| 243 | + "In the next code block we make a new model and run it. Note that because we are using the LinearDiffuser which may result in depositing material we must specify a rock_id in the RockBlock `run_one_step` method.\n", |
| 244 | + "\n", |
| 245 | + "We also are handling the model grid boundary conditions differently than in the last example, setting the boundaries on the left and right sides to closed. " |
240 | 246 | ] |
241 | 247 | }, |
242 | 248 | { |
243 | 249 | "cell_type": "code", |
244 | 250 | "execution_count": null, |
245 | | - "metadata": { |
246 | | - "collapsed": true |
247 | | - }, |
| 251 | + "metadata": {}, |
248 | 252 | "outputs": [], |
249 | 253 | "source": [ |
250 | | - "mg2 = RasterModelGrid((50, 50), 100)\n", |
| 254 | + "mg2 = RasterModelGrid((100, 100), 200)\n", |
| 255 | + "mg2.set_closed_boundaries_at_grid_edges(True, False, True, False)\n", |
251 | 256 | "z2 = mg2.add_zeros('node', 'topographic__elevation') \n", |
252 | 257 | "random_field = 0.01*np.random.randn(mg2.size('node'))\n", |
253 | 258 | "z2 += random_field - random_field.min()\n", |
254 | 259 | "\n", |
255 | | - "thicknesses2 = [1000]\n", |
| 260 | + "thicknesses2 = [10000]\n", |
256 | 261 | "ids2 =[0]\n", |
257 | 262 | "\n", |
258 | 263 | "attrs2 = {'K_sp': {0: 0.0001,\n", |
259 | | - " 1: 0.00001}}\n", |
| 264 | + " 1: 0.00001},\n", |
| 265 | + " 'D': {0: 0.4,\n", |
| 266 | + " 1: 0.001}}\n", |
260 | 267 | "\n", |
261 | 268 | "rb2 = RockBlock(mg2, thicknesses2, ids2, attrs=attrs2)\n", |
262 | 269 | "\n", |
263 | | - "nts = 400\n", |
264 | | - "U = 0.001\n", |
| 270 | + "nts = 500\n", |
| 271 | + "U = 0.005\n", |
265 | 272 | "dt = 1000\n", |
266 | 273 | "\n", |
267 | 274 | "fa2 = FlowAccumulator(mg2)\n", |
268 | 275 | "sp2 = FastscapeEroder(mg2, K_sp='K_sp')\n", |
| 276 | + "ld2 = LinearDiffuser(mg2, linear_diffusivity='D')\n", |
269 | 277 | "\n", |
270 | 278 | "out_fields = ['topographic__elevation',\n", |
271 | | - " 'K_sp', \n", |
272 | 279 | " 'rock_type__id']\n", |
273 | 280 | "\n", |
274 | | - "ds2 = xr.Dataset(data_vars={'topographic__elevation' : (('y', 'x', 't'), np.empty((mg2.shape[0], mg2.shape[1], nts))),\n", |
275 | | - " 'K_sp' : (('y', 'x', 't'), np.empty((mg2.shape[0], mg2.shape[1], nts))),\n", |
276 | | - " 'rock_type__id': (('y', 'x', 't'), np.empty((mg2.shape[0], mg2.shape[1], nts)))},\n", |
277 | | - " coords={'x': mg2.x_of_node.reshape(mg2.shape)[0,:],\n", |
278 | | - " 'y': mg2.y_of_node.reshape(mg2.shape)[:, 1],\n", |
279 | | - " 't': dt*np.arange(nts)/1e6})\n", |
| 281 | + "out_fields = ['topographic__elevation',\n", |
| 282 | + " 'rock_type__id']\n", |
| 283 | + "\n", |
| 284 | + "ds2 = xr.Dataset(data_vars={'topographic__elevation' : (('t', 'y', 'x'), np.empty((nts, mg2.shape[0], mg2.shape[1]))),\n", |
| 285 | + " 'rock_type__id': (('t', 'y', 'x'), np.empty((nts, mg2.shape[0], mg2.shape[1])))},\n", |
| 286 | + " coords={'x': mg2.x_of_node.reshape(mg2.shape)[0,:],\n", |
| 287 | + " 'y': mg2.y_of_node.reshape(mg2.shape)[:, 1],\n", |
| 288 | + " 't': dt*np.arange(nts)/1e6})\n", |
280 | 289 | "half_nts = int(nts/2)\n", |
281 | 290 | "for i in range(half_nts):\n", |
282 | 291 | " fa2.run_one_step()\n", |
283 | | - " sp2.run_one_step(dt = dt)\n", |
| 292 | + " sp2.run_one_step(dt=dt)\n", |
| 293 | + " ld2.run_one_step(dt=dt)\n", |
284 | 294 | " dz_ad2 = np.zeros(mg2.size('node'))\n", |
285 | 295 | " dz_ad2[mg2.core_nodes] = U * dt\n", |
286 | 296 | " z2 += dz_ad2\n", |
287 | | - " rb2.run_one_step(dz_advection = dz_ad2)\n", |
| 297 | + " rb2.run_one_step(dz_advection = dz_ad2, rock_id=0)\n", |
288 | 298 | " \n", |
289 | 299 | " for of in out_fields:\n", |
290 | | - " ds2[of][:,:,i] = mg2['node'][of].reshape(mg2.shape)\n" |
| 300 | + " ds2[of][i,:,:] = mg2['node'][of].reshape(mg2.shape)" |
291 | 301 | ] |
292 | 302 | }, |
293 | 303 | { |
294 | 304 | "cell_type": "markdown", |
295 | 305 | "metadata": {}, |
296 | | - "source": [] |
| 306 | + "source": [ |
| 307 | + "After the first half of run time, let's look at the topography. " |
| 308 | + ] |
297 | 309 | }, |
298 | 310 | { |
299 | 311 | "cell_type": "code", |
|
307 | 319 | { |
308 | 320 | "cell_type": "markdown", |
309 | 321 | "metadata": {}, |
310 | | - "source": [] |
| 322 | + "source": [ |
| 323 | + "We can see that we have developed ridges and valleys as we'd expect from a model with stream power erosion and linear diffusion. \n", |
| 324 | + "\n", |
| 325 | + "Next we will create some volcanic deposits that fill the channels in our model." |
| 326 | + ] |
311 | 327 | }, |
312 | 328 | { |
313 | 329 | "cell_type": "code", |
314 | 330 | "execution_count": null, |
315 | 331 | "metadata": {}, |
316 | 332 | "outputs": [], |
317 | 333 | "source": [ |
318 | | - "volcano_deposits = np.zeros(mg2.size('node'))\n", |
319 | | - "da_big_enough = mg2['node']['drainage_area']>1e4\n", |
320 | | - "volcano_deposits[da_big_enough] = 30.0\n", |
321 | | - "volcano_deposits[mg2.boundary_nodes] = 0.0\n", |
322 | | - "rb2.add_layer(volcano_deposits, rock_id=1)\n", |
| 334 | + "volcanic_deposits = np.zeros(mg2.size('node'))\n", |
| 335 | + "da_big_enough = mg2['node']['drainage_area']>5e4\n", |
323 | 336 | "\n", |
324 | | - "imshow_grid(mg2, da_big_enough)" |
| 337 | + "topo_difference_from_top = mg2['node']['topographic__elevation'].max() - mg2['node']['topographic__elevation']\n", |
| 338 | + "\n", |
| 339 | + "volcanic_deposits[da_big_enough] = 0.5 * topo_difference_from_top[da_big_enough]\n", |
| 340 | + "volcanic_deposits[mg2.boundary_nodes] = 0.0\n", |
| 341 | + "\n", |
| 342 | + "z2 += volcanic_deposits\n", |
| 343 | + "rb2.run_one_step(rock_id=1)\n", |
| 344 | + "\n", |
| 345 | + "imshow_grid(mg2, volcanic_deposits)" |
325 | 346 | ] |
326 | 347 | }, |
327 | 348 | { |
328 | 349 | "cell_type": "markdown", |
329 | 350 | "metadata": {}, |
330 | | - "source": [] |
| 351 | + "source": [ |
| 352 | + "We should expect that the locations of our valleys and ridges change as the river system encouters the much stronger volcanic rock. " |
| 353 | + ] |
331 | 354 | }, |
332 | 355 | { |
333 | 356 | "cell_type": "code", |
334 | 357 | "execution_count": null, |
335 | | - "metadata": { |
336 | | - "collapsed": true |
337 | | - }, |
| 358 | + "metadata": {}, |
338 | 359 | "outputs": [], |
339 | 360 | "source": [ |
340 | 361 | "for i in range(half_nts, nts):\n", |
341 | 362 | " fa2.run_one_step()\n", |
342 | | - " sp2.run_one_step(dt = dt)\n", |
343 | | - " dz_ad = np.zeros(mg2.size('node'))\n", |
344 | | - " dz_ad[mg2.core_nodes] = U * dt\n", |
345 | | - " z2 += dz_ad\n", |
346 | | - " rb2.run_one_step(dz_advection = dz_ad)\n", |
| 363 | + " sp2.run_one_step(dt=dt)\n", |
| 364 | + " ld2.run_one_step(dt=dt)\n", |
| 365 | + " dz_ad2 = np.zeros(mg2.size('node'))\n", |
| 366 | + " dz_ad2[mg2.core_nodes] = U * dt\n", |
| 367 | + " z2 += dz_ad2\n", |
| 368 | + " rb2.run_one_step(dz_advection = dz_ad2, rock_id=0)\n", |
347 | 369 | " \n", |
348 | 370 | " for of in out_fields:\n", |
349 | | - " ds2[of][:,:,i] = mg2['node'][of].reshape(mg2.shape)" |
| 371 | + " ds2[of][i,:,:] = mg2['node'][of].reshape(mg2.shape)" |
350 | 372 | ] |
351 | 373 | }, |
352 | 374 | { |
353 | 375 | "cell_type": "markdown", |
354 | 376 | "metadata": {}, |
355 | | - "source": [] |
| 377 | + "source": [ |
| 378 | + "Now that the model has run, let's plot the final elevation" |
| 379 | + ] |
356 | 380 | }, |
357 | 381 | { |
358 | 382 | "cell_type": "code", |
|
366 | 390 | { |
367 | 391 | "cell_type": "markdown", |
368 | 392 | "metadata": {}, |
369 | | - "source": [] |
| 393 | + "source": [ |
| 394 | + "And now a HoloView Plot that lets us explore the time evolution of the topography" |
| 395 | + ] |
370 | 396 | }, |
371 | 397 | { |
372 | 398 | "cell_type": "code", |
|
384 | 410 | ] |
385 | 411 | }, |
386 | 412 | { |
387 | | - "cell_type": "code", |
388 | | - "execution_count": null, |
389 | | - "metadata": { |
390 | | - "collapsed": true |
391 | | - }, |
392 | | - "outputs": [], |
393 | | - "source": [] |
394 | | - }, |
395 | | - { |
396 | | - "cell_type": "code", |
397 | | - "execution_count": null, |
| 413 | + "cell_type": "markdown", |
398 | 414 | "metadata": { |
399 | 415 | "collapsed": true |
400 | 416 | }, |
401 | | - "outputs": [], |
402 | | - "source": [] |
| 417 | + "source": [ |
| 418 | + "Sure enough, the volcanic deposits impact the location of the ridges and valleys. The old valleys become ridges because it takes so much time for them to be eroded. \n", |
| 419 | + "\n", |
| 420 | + "You can explore how this changes as the thickness of the deposit changes and as the relative erodabilities change. \n", |
| 421 | + "\n", |
| 422 | + "\n", |
| 423 | + "## The end.\n", |
| 424 | + "\n", |
| 425 | + "Nice work getting to the end of the tutorial!\n", |
| 426 | + "\n", |
| 427 | + "For more detailed information about the [RockBlock](http://landlab.readthedocs.io/en/release/landlab.layers.rockblock.html) and [LayeredRockBlock](http://landlab.readthedocs.io/en/release/landlab.layers.layeredrockblock.html) objects, check out their detailed documentation. \n", |
| 428 | + "\n", |
| 429 | + "# **Click [here](https://github.com/landlab/landlab/wiki/Tutorials) for more Landlab tutorials**" |
| 430 | + ] |
403 | 431 | } |
404 | 432 | ], |
405 | 433 | "metadata": { |
|
0 commit comments