************* Hydrodynamics ************* .. currentmodule:: pyDeltaRCM.water_tools pyDeltaRCM approximates hydrodynamics through the use of a weighted random walk. See [1]_ and [2]_ for a complete description of hydrodynamic assumptions in the DeltaRCM model. In this documentation, we focus on the details of *model implementation*, rather than *model design*. The water routing operations are orchestrated by :obj:~water_tools.route_water; the following sections narrate the sequence of events within a single call of this method. Routing individual water parcels ================================ Probabilities for water parcel routing *to all neighbors and to self* for *each cell* are computed *once* at the beginning of the water routing routine (:obj:~water_tools.get_water_weight_array called from :obj:~water_tools.run_water_iteration). Water routing probability for a given cell :math:j to neighbor cell :math:i is computed according to: .. math:: w_i = \frac{\frac{1}{R_i} \max(0, \mathbf{F}\cdot\mathbf{d_i})}{\Delta i}, where :math:\mathbf{F} is the local routing direction and :math:\mathbf{d_i} is a unit vector pointing to neighbor :math:i from cell :math:j, and :math:\Delta_i is the cellular distance to neighbor :math:i (:math:1 for cells in main compass directions and :math:\sqrt{2} for corner cells. :math:R_i is a flow resistance estimated as an inverse function of local water depth (:math:h_i): .. math:: R_i = \frac{1}{{h_i}^\theta} The exponent :math:\theta takes a value of unity by default for water routing (:attr:~pyDeltaRCM.DeltaModel.theta_water, :doc:/reference/model/yaml_defaults), leading to routing weight for neighbor cell :math:i: .. math:: w_i = \frac{h_i \max(0, \mathbf{F}\cdot\mathbf{d_i})}{\Delta i}, These weights above are calculated only for wet neighbor cells; all dry neighbor cells take a weight value of 0 (:obj:~water_tools._get_weight_at_cell_water). Finally, probability for routing from cell :math:j to cell :math:i is calculated as: .. math:: p_i = \frac{w_i}{\sum^8_{nb=1} w_{nb}}, i=1, 2, \ldots, 8 Weights are accumulated for 8 neighbors and a probability of 0 is assigned to moving from cell :math:j to cell :math:j (i.e., no movement). These 9 probabilities are organized into an array self.water_weights with shape (:obj:L, :obj:W, 9). The following figure shows several examples of locations within the model domain, and the corresponding water routing weights determined for that location. .. plot:: water_tools/water_weights_examples.py Because probabilities are computed for all locations once at the beginning of water iteration, all water parcels can be routed *in parallel* step-by-step in :obj:~water_tools.run_water_iteration. During iteration, the direction of the random walk is chosen for each parcel via :obj:_choose_next_directions, which internally uses :func:~pyDeltaRCM.shared_tools.random_pick for randomness. For example, see the random walks of several parcels below: .. plot:: water_tools/run_water_iteration.py .. todo:: add sentence or two above about check_for_loops. Water routing completes when all water parcels have either 1) reached the model domain boundary, 2) taken a number of steps exceeding :attr:~pyDeltaRCM.model.DeltaModel.stepmax, or 3) been removed from further routing via the :obj:_check_for_loops function. Combining parcels into free surface =================================== Following the routing of water parcels, these walks must be converted in some meaningful way to a model field representing a free surface (i.e., the water stage). First, the :meth:~water_tools.compute_free_surface is called, which takes as input the current bed elevation, and the path of each water parcel (top row in figure below). .. plot:: water_tools/compute_free_surface_inputs.py The :meth:~water_tools.compute_free_surface method internally calls the :func:_accumulate_free_surface_walks function to determine 1) the number of times each cell has been visited by a water parcel (sfc_visit), and 2) the *total sum of expected elevations* of the water surface at each cell (sfc_sum). :func:_accumulate_free_surface_walks itself iterates through each water parcel, beginning from the end-point of the path, and working upstream; note that parcels that have been determined to "loop" (:func:_check_for_loops and described above) are excluded from computation in determining the free surface. While downstream of the land-ocean boundary (determined by a depth-or-velocity threshold), the water surface elevation is assumed to be 0, whereas upstream of this boundary, the predicted elevation of the water surface is determined by the distance from the previously identified water surface elevation and the background land slope (:attr:~pyDeltaRCM.DeltaModel.S0), such the the water surface maintains an approximately constant slope for each parcel pathway. .. plot:: water_tools/_accumulate_free_surface_walks.py The algorithm tracks the number of times each cell has been visited by a water parcel (sfc_visit), and the *total sum of expected elevations* of the water surface at each cell (sfc_sum), by adding the predicted surface elevation of each parcel step while iterating through each step of each parcel. Next, the output from :func:_accumulate_free_surface_walks is used to calculate a new stage surface (H_new) based only on the water parcel paths and expected water surface elevations, approximately as H_new = sfc_sum / sfc_visit. The updated water surface is combined with the previous timestep's water surface and an under-relaxation coefficient (:attr:~pyDeltaRCM.DeltaModel.omega_sfc). .. plot:: water_tools/compute_free_surface_outputs.py With a new free surface computed, a few final operations prepare the surface for boundary condition updates and eventually being passed to the sediment routing operations (inside :meth:~water_tools.finalize_free_surface). A non-linear smoothing operation is applied to the free surface, whereby wet cells are iteratively averaged with neighboring wet cells to yield an overall smoother surface. The smoothing is handled by :func:_smooth_free_surface and depends on the number of iterations (:attr:~pyDeltaRCM.model.DeltaModel.Nsmooth) and a weighting coefficient (:attr:~pyDeltaRCM.model.DeltaModel.Csmooth). .. plot:: water_tools/_smooth_free_surface.py Finally, a :meth:~water_tools.flooding_correction is applied to the domain. In this correction, all "dry" cells (a cell where the flow depth is less than the dry_depth) are checked for any neighboring cells where the water surface elevation (stage) is higher than the bed elevation of the dry cell. If this condition is met for a given dry cell, the dry cell is flooded: the stage of the dry cell is set to the maximum stage of neighboring cells. .. plot:: water_tools/flooding_correction.py Similar to :func:~_smooth_free_surface described above, :meth:~water_tools.flooding_correction acts to remove roughness in the water surface and contributes to :ref:model stability . Finalizing and boundary conditions to sediment routing ====================================================== The final step of the water routing operations in each call to :obj:~water_tools.route_water is the updating of model fields, and application of a few corrections and boundary conditions. These operations are handled within :obj:~water_tools.finalize_water_iteration. First, the stage field is limited to elevations above or equal to sea level H_SL. Then, the depth field is updated as the vertical distance between the stage field and the bed elevation eta. These operations ensure that these fields are in agreement over the entire model domain. Next, methods :obj:~water_tools.update_flow_field and :obj:~water_tools.update_velocity_field are called, which handle the updating of water discharge and water velocity fields, respectively. .. note:: The next step in the model update sequence is sediment routing (:obj:~pyDeltaRCM.sed_tools.sed_tools.route_sediment). For more information on the next stage, see :doc:morphodynamics`. References ========== .. [1] A reduced-complexity model for river delta formation – Part 1: Modeling deltas with channel dynamics, M. Liang, V. R. Voller, and C. Paola, Earth Surf. Dynam., 3, 67–86, 2015. https://doi.org/10.5194/esurf-3-67-2015 .. [2] A reduced-complexity model for river delta formation – Part 2: Assessment of the flow routing scheme, M. Liang, N. Geleynse, D. A. Edmonds, and P. Passalacqua, Earth Surf. Dynam., 3, 87–104, 2015. https://doi.org/10.5194/esurf-3-87-2015