|
12 | 12 | # name: python3 |
13 | 13 | # --- |
14 | 14 |
|
15 | | -# This example demonstrates the `MFArray` class. |
| 15 | +# # Array variables |
| 16 | +# |
| 17 | +# This example demonstrates how to work with array input variables. |
| 18 | +# |
| 19 | +# ## Overview |
| 20 | +# |
| 21 | +# FloPy works natively with NumPy arrays. Array input data can be provided |
| 22 | +# as `ndarray` (or anything acting like one). FloPy also provides an array |
| 23 | +# subclass `MFArray` supporting some special behaviors: |
| 24 | +# |
| 25 | +# - more efficient memory usage for constant arrays |
| 26 | +# - convenient layered array manipulation |
| 27 | +# - applying a multiplication factor |
| 28 | +# |
| 29 | +# TODO: rewrite the io stuff (external/internal) once that is moved to a |
| 30 | +# separate layer from MFArray |
16 | 31 |
|
17 | 32 | # + |
18 | 33 | from pathlib import Path |
| 34 | +from tempfile import TemporaryDirectory |
19 | 35 |
|
| 36 | +import flopy |
20 | 37 | import git |
21 | 38 | import matplotlib.pyplot as plt |
22 | 39 | import numpy as np |
|
271 | 288 | mlmfa.sum() |
272 | 289 |
|
273 | 290 | mlmfa.min(), mlmfa.mean(), mlmfa.max() |
| 291 | + |
| 292 | + |
| 293 | +# ## Grid-shaped array data |
| 294 | +# |
| 295 | +# Most MODFLOW array data are two (row, column) or three (layer, |
| 296 | +# row, column) dimensional and represent data on the model grid. |
| 297 | +# grid. Other MODFLOW array data contain data by stress period. |
| 298 | +# The following list summarizes the types of MODFLOW array data. |
| 299 | + |
| 300 | +# * Time-invariant multi-dimensional array data. This includes: |
| 301 | +# 1. One and two dimensional arrays that do not have a layer dimension. |
| 302 | +# Examples include `top`, `delc`, and `delr`. |
| 303 | +# 2. Three dimensional arrays that can contain a layer dimension. |
| 304 | +# Examples include `botm`, `idomain`, and `k`. |
| 305 | +# * Transient arrays that can change with time and therefore contain arrays of |
| 306 | +# data for one or more stress periods. Examples include `irch` and |
| 307 | +# `recharge` in the `RCHA` package. |
| 308 | +# |
| 309 | +# In the example below a three dimensional ndarray is constructed for the |
| 310 | +# `DIS` package's `botm` array. First, the a simulation and groundwater-flow |
| 311 | +# model are set up. |
| 312 | + |
| 313 | +# set up where simulation workspace will be stored |
| 314 | +temp_dir = TemporaryDirectory() |
| 315 | +workspace = temp_dir.name |
| 316 | +name = "grid_array_example" |
| 317 | + |
| 318 | +# create the FloPy simulation and tdis objects |
| 319 | +sim = flopy.mf6.MFSimulation( |
| 320 | + sim_name=name, exe_name="mf6", version="mf6", sim_ws=workspace |
| 321 | +) |
| 322 | +tdis = flopy.mf6.modflow.mftdis.ModflowTdis( |
| 323 | + sim, |
| 324 | + pname="tdis", |
| 325 | + time_units="DAYS", |
| 326 | + nper=2, |
| 327 | + perioddata=[(1.0, 1, 1.0), (1.0, 1, 1.0)], |
| 328 | +) |
| 329 | +# create the Flopy groundwater flow (gwf) model object |
| 330 | +model_nam_file = f"{name}.nam" |
| 331 | +gwf = flopy.mf6.ModflowGwf(sim, modelname=name, model_nam_file=model_nam_file) |
| 332 | +# create the flopy iterative model solver (ims) package object |
| 333 | +ims = flopy.mf6.modflow.mfims.ModflowIms(sim, pname="ims", complexity="SIMPLE") |
| 334 | + |
| 335 | +# Then a three-dimensional ndarray of floating point values is created using |
| 336 | +# numpy's `linspace` method. |
| 337 | + |
| 338 | +bot = np.linspace(-50.0 / 3.0, -3.0, 3) |
| 339 | +delrow = delcol = 4.0 |
| 340 | + |
| 341 | +# The `DIS` package is then created passing the three-dimensional array to the |
| 342 | +# `botm` parameter. The `botm` array defines the model's cell bottom |
| 343 | +# elevations. |
| 344 | + |
| 345 | +dis = flopy.mf6.modflow.mfgwfdis.ModflowGwfdis( |
| 346 | + gwf, |
| 347 | + pname="dis", |
| 348 | + nogrb=True, |
| 349 | + nlay=3, |
| 350 | + nrow=10, |
| 351 | + ncol=10, |
| 352 | + delr=delrow, |
| 353 | + delc=delcol, |
| 354 | + top=0.0, |
| 355 | + botm=bot, |
| 356 | +) |
| 357 | + |
| 358 | +# ## Adding MODFLOW Grid Array Data |
| 359 | +# MODFLOW grid array data, like the data found in the `NPF` package's |
| 360 | +# `GridData` block, can be specified as: |
| 361 | +# |
| 362 | +# 1. A constant value |
| 363 | +# 2. A n-dimensional list |
| 364 | +# 3. A numpy ndarray |
| 365 | +# |
| 366 | +# Additionally, layered grid data (generally arrays with a layer dimension) can |
| 367 | +# be specified by layer. |
| 368 | +# |
| 369 | +# In the example below `icelltype` is specified as constants by layer, `k` is |
| 370 | +# specified as a numpy ndarray, `k22` is specified as an array by layer, and |
| 371 | +# `k33` is specified as a constant. |
| 372 | + |
| 373 | +# First `k` is set up as a 3 layer, by 10 row, by 10 column array with all |
| 374 | +# values set to 10.0 using numpy's full method. |
| 375 | + |
| 376 | +k = np.full((3, 10, 10), 10.0) |
| 377 | + |
| 378 | +# Next `k22` is set up as a three dimensional list of nested lists. This |
| 379 | +# option can be useful for those that are familiar with python lists but are |
| 380 | +# not familiar with the numpy library. |
| 381 | + |
| 382 | +k22_row = [] |
| 383 | +for row in range(0, 10): |
| 384 | + k22_row.append(8.0) |
| 385 | +k22_layer = [] |
| 386 | +for col in range(0, 10): |
| 387 | + k22_layer.append(k22_row) |
| 388 | +k22 = [k22_layer, k22_layer, k22_layer] |
| 389 | + |
| 390 | +# `K33` is set up as a single constant value. Whenever an array has all the |
| 391 | +# same values the easiest and most efficient way to set it up is as a constant |
| 392 | +# value. Constant values also take less space to store. |
| 393 | + |
| 394 | +k33 = 1.0 |
| 395 | + |
| 396 | +# The `k`, `k22`, and `k33` values defined above are then passed in on |
| 397 | +# construction of the npf package. |
| 398 | + |
| 399 | +npf = flopy.mf6.ModflowGwfnpf( |
| 400 | + gwf, |
| 401 | + pname="npf", |
| 402 | + save_flows=True, |
| 403 | + icelltype=[1, 1, 1], |
| 404 | + k=k, |
| 405 | + k22=k22, |
| 406 | + k33=k33, |
| 407 | + xt3doptions="xt3d rhs", |
| 408 | + rewet_record="REWET WETFCT 1.0 IWETIT 1 IHDWET 0", |
| 409 | +) |
| 410 | + |
| 411 | +# ### Layered Data |
| 412 | +# |
| 413 | +# When we look at what will be written to the npf input file, we |
| 414 | +# see that the entire `npf.k22` array is written as one long array with the |
| 415 | +# number of values equal to `nlay` * `nrow` * `ncol`. And this whole-array |
| 416 | +# specification may be of use in some cases. Often times, however, it is |
| 417 | +# easier to work with each layer separately. An `MFArray` object, such as |
| 418 | +# `npf.k22` can be converted to a layered array as follows. |
| 419 | + |
| 420 | +npf.k22.make_layered() |
| 421 | + |
| 422 | +# By changing `npf.k22` to layered, we are then able to manage each layer |
| 423 | +# separately. Before doing so, however, we need to pass in data that can be |
| 424 | +# separated into three layers. An array of the correct size is one option. |
| 425 | + |
| 426 | +shp = npf.k22.array.shape |
| 427 | +a = np.arange(shp[0] * shp[1] * shp[2]).reshape(shp) |
| 428 | +npf.k22 = a |
| 429 | + |
| 430 | +# Now that `npf.k22` has been set to be layered, if we print information about |
| 431 | +# it, we see that each layer is stored separately, however, `npf.k22.array` |
| 432 | +# will still return a full three-dimensional array. |
| 433 | + |
| 434 | +type(npf.k22) |
| 435 | +npf.k22 |
| 436 | + |
| 437 | +# We also see that each layer is printed separately to the npf |
| 438 | +# Package input file, and that the LAYERED keyword is activated: |
| 439 | + |
| 440 | +npf.k22 |
| 441 | + |
| 442 | +# Working with a layered array provides lots of flexibility. For example, |
| 443 | +# constants can be set for some layers, but arrays for others: |
| 444 | + |
| 445 | +npf.k22.set_data([1, a[2], 200]) |
| 446 | +npf.k22 |
| 447 | + |
| 448 | +# The array can be interacted with as usual for NumPy arrays: |
| 449 | +npf.k22 = np.stack( |
| 450 | + [ |
| 451 | + 100 * np.ones((10, 10)), |
| 452 | + 50 * np.ones((10, 10)), |
| 453 | + 30 * np.ones((10, 10)), |
| 454 | + ] |
| 455 | +) |
| 456 | +npf.k22 |
| 457 | + |
| 458 | +# ## Adding MODFLOW Stress Period Array Data |
| 459 | +# Transient array data spanning multiple stress periods must be specified as a |
| 460 | +# dictionary of arrays, where the dictionary key is the stress period, |
| 461 | +# expressed as a zero-based integer, and the dictionary value is the grid |
| 462 | +# data for that stress period. |
| 463 | + |
| 464 | +# In the following example a `RCHA` package is created. First a dictionary |
| 465 | +# is created that contains recharge for the model's two stress periods. |
| 466 | +# Recharge is specified as a constant value in this example, though it could |
| 467 | +# also be specified as a 3-dimensional ndarray or list of lists. |
| 468 | + |
| 469 | +rch_sp1 = 0.01 |
| 470 | +rch_sp2 = 0.03 |
| 471 | +rch_spd = {0: rch_sp1, 1: rch_sp2} |
| 472 | + |
| 473 | +# The `RCHA` package is created and the dictionary constructed above is passed |
| 474 | +# in as the `recharge` parameter. |
| 475 | + |
| 476 | +rch = flopy.mf6.ModflowGwfrcha( |
| 477 | + gwf, readasarrays=True, pname="rch", print_input=True, recharge=rch_spd |
| 478 | +) |
| 479 | + |
| 480 | +# Below the `NPF` `k` array is retrieved using the various methods highlighted |
| 481 | +# above. |
| 482 | + |
| 483 | +# First, view the `k` array. |
| 484 | + |
| 485 | +npf.k |
| 486 | + |
| 487 | +# `repr` gives a string representation of the data. |
| 488 | + |
| 489 | +repr(npf.k) |
| 490 | + |
| 491 | +# `str` gives a similar string representation of the data. |
| 492 | + |
| 493 | +str(npf.k) |
| 494 | + |
| 495 | +# Next, view the 4-dimensional array. |
| 496 | + |
| 497 | +rch.recharge |
| 498 | + |
| 499 | +# `repr` gives a string representation of the data. |
| 500 | + |
| 501 | +repr(rch.recharge) |
| 502 | + |
| 503 | +# str gives a similar representation of the data. |
| 504 | + |
| 505 | +str(rch.recharge) |
0 commit comments