Exemple #1
0
    def __init__(self, input_file=None, params=None):
        """Initialize the LinearDiffusionModel."""
        
        # Call ErosionModel's init
        super(KinwaveModel, self).__init__(input_file=input_file,
                                           params=params)

        # Get input parameters: duration for a runoff (i.e., storm or snowmelt)
        # event, interval of time from the end of one event to the next, and
        # rate of runoff generation (in mm/hr) during an event.
        self.runoff_duration = self.params['runoff__duration']
        self.interstorm_duration = self.params['interstorm__duration']
        self.runoff_rate = self.params['runoff__rate'] / 3.6e6
        
        # A "cycle" is a runoff event plus the interlude before the next event.
        self.cycle_duration = self.runoff_duration + self.interstorm_duration
        
        # Runoff continues for some time after runoff generation ceases. Here
        # we set the amount of time we actively calculate flow. After this
        # time period, we ignore flow for the remainder of the cycle. But if
        # the user-specified hydrograph duration is longer than our cycle, we
        # truncate at the cycle duration, because we'll start computing flow
        # again at the start of the next cycle.
        self.hydrograph_duration = min(self.cycle_duration,
            self.params['hydrograph__maximum_duration'])

        # This variable keeps track of how far we are in one cycle.
        self.current_time_in_cycle = 0.0

        # Instantiate a KinwaveImplicitOverlandFlow
        self.water_router = KinwaveImplicitOverlandFlow(self.grid)
def test_initialization():
    """Test initialization with various parameters."""
    rg = RasterModelGrid((3, 4), xy_spacing=2.0)
    rg.add_zeros("topographic__elevation", at="node")
    kw = KinwaveImplicitOverlandFlow(rg)

    # Make sure fields have been created
    for field_name in kw._info:
        if kw._info[field_name]["mapping"] == "node":
            assert field_name in kw.grid.at_node
        elif kw._info[field_name]["mapping"] == "link":
            assert field_name in kw.grid.at_link

    # Re-initialize, this time with fields already existing in the grid
    # (this triggers the "if" instead of "else" in the field setup in init)
    kw = KinwaveImplicitOverlandFlow(rg)
def test_first_iteration():
    """Test stuff that happens only on first iteration"""

    # Create a basic ramp
    rg = RasterModelGrid((10, 10), spacing=(2, 2))
    rg.add_field("topographic__elevation", 0.1 * rg.node_y, at="node")

    # Create component and run it
    kw = KinwaveImplicitOverlandFlow(rg)
    kw.run_one_step(1.0)

    # Max gradient should be 0.1, and min should be zero
    assert round(np.amax(kw.grid.at_link["topographic__gradient"]), 2) == 0.1
    assert round(np.amin(kw.grid.at_link["topographic__gradient"]), 2) == 0.0
    assert round(np.amax(kw.sqrt_slope), 3) == 0.316
    assert round(np.amax(kw.grad_width_sum), 3) == 0.632
    assert round(np.amax(kw.alpha), 3) == 15.811
def test_first_iteration():
    """Test stuff that happens only on first iteration"""
    
    # Create a basic ramp
    rg = RasterModelGrid((10,10), spacing=(2, 2))
    rg.add_field('topographic__elevation', 0.1 * rg.node_y, at='node')

    # Create component and run it
    kw = KinwaveImplicitOverlandFlow(rg)
    kw.run_one_step(1.0)

    # Max gradient should be 0.1, and min should be zero
    assert round(np.amax(kw.grid.at_link['topographic__gradient']), 2) == 0.1
    assert round(np.amin(kw.grid.at_link['topographic__gradient']), 2) == 0.0
    assert round(np.amax(kw.sqrt_slope), 3) == 0.316
    assert round(np.amax(kw.grad_width_sum), 3) == 0.632
    assert round(np.amax(kw.alpha), 3) == 15.811
Exemple #5
0
def test_initialization():
    """Test initialization with various parameters.
    """
    rg = RasterModelGrid((3, 4), 2.0)
    rg.add_zeros('node', 'topographic__elevation')
    kw = KinwaveImplicitOverlandFlow(rg)

    # Make sure fields have been created
    for field_name in kw._var_mapping:
        if kw._var_mapping[field_name] == 'node':
            assert field_name in kw.grid.at_node
        elif kw._var_mapping[field_name] == 'link':
            assert field_name in kw.grid.at_link

    # Re-initialize, this time with fields already existing in the grid
    # (this triggers the "if" instead of "else" in the field setup in init)
    kw = KinwaveImplicitOverlandFlow(rg)
def test_curved_surface():
    """Test flow across a curved surface."""

    # Create a grid
    rg = RasterModelGrid((10,10), spacing=(2, 2))
    rg.add_field('topographic__elevation', 3.*rg.node_x**2 + rg.node_y**2,
                 at='node')

    # Create component and run it
    kw = KinwaveImplicitOverlandFlow(rg)
    for i in range(8):
        kw.run_one_step(1.0, runoff_rate=0.001)

    # The inflow discharge to each cell at steady state should equal the
    # runoff rate times the "inflow" drainage area, which is the total drainage
    # area minus the area of the cell itself. Here we'll test a column of core
    # nodes across the middle of the domain.
    area = rg.at_node['drainage_area']
    runoff_rate = 0.001
    unit_area = 4.0
    for i in range(15, 95, 10):
        assert round(kw.disch_in[i], 6) == round(runoff_rate * (area[i] - unit_area), 6)
def test_curved_surface():
    """Test flow across a curved surface."""

    # Create a grid
    rg = RasterModelGrid((10, 10), spacing=(2, 2))
    rg.add_field("topographic__elevation",
                 3. * rg.node_x**2 + rg.node_y**2,
                 at="node")

    # Create component and run it
    kw = KinwaveImplicitOverlandFlow(rg)
    for i in range(8):
        kw.run_one_step(1.0, runoff_rate=0.001)

    # The inflow discharge to each cell at steady state should equal the
    # runoff rate times the "inflow" drainage area, which is the total drainage
    # area minus the area of the cell itself. Here we'll test a column of core
    # nodes across the middle of the domain.
    area = rg.at_node["drainage_area"]
    runoff_rate = 0.001
    unit_area = 4.0
    for i in range(15, 95, 10):
        assert round(kw.disch_in[i],
                     6) == round(runoff_rate * (area[i] - unit_area), 6)
def test_steady_basic_ramp():
    """Run to steady state with basic ramp"""

    # Create a basic ramp
    rg = RasterModelGrid((10,10), spacing=(2, 2))
    rg.add_field('topographic__elevation', 0.1 * rg.node_y, at='node')

    # Create component and run it
    kw = KinwaveImplicitOverlandFlow(rg)
    for i in range(12):
        kw.run_one_step(1.0, runoff_rate=0.001)

    # Look at a column of nodes down the middle. The inflow from uphill should
    # be, from top to bottom: 0, 0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028
    assert_equal(kw.disch_in[85], 0.0)
    assert_equal(round(kw.disch_in[75], 3), 0.004)
    assert_equal(round(kw.disch_in[65], 3), 0.008)
    assert_equal(round(kw.disch_in[55], 3), 0.012)
    assert_equal(round(kw.disch_in[45], 3), 0.016)
    assert_equal(round(kw.disch_in[35], 3), 0.020)
    assert_equal(round(kw.disch_in[25], 3), 0.024)
    assert_equal(round(kw.disch_in[15], 3), 0.028)

    # Try with passing in runoff
    kw = KinwaveImplicitOverlandFlow(rg, runoff_rate=360.0)
    kw.depth[:] = 0.0
    for i in range(22):
        kw.run_one_step(1.0)

    # Again, look at a column of nodes down the middle. The inflow from uphill 
    # should now be 1/10 of the prior example.
    assert_equal(round(kw.disch_in[75], 4), 0.0004)
    assert_equal(round(kw.disch_in[65], 4), 0.0008)
    assert_equal(round(kw.disch_in[55], 4), 0.0012)
    assert_equal(round(kw.disch_in[45], 4), 0.0016)
    assert_equal(round(kw.disch_in[35], 4), 0.0020)
    assert_equal(round(kw.disch_in[25], 4), 0.0024)
    assert_equal(round(kw.disch_in[15], 4), 0.0028)

    # Try with default runoff rate of 1 mm/hr = 2.78e-7 m/s
    kw = KinwaveImplicitOverlandFlow(rg)
    assert_equal(round(kw.runoff_rate * 1.0e7, 2), 2.78)
    kw.depth[:] = 0.0
    for i in range(18):
        kw.run_one_step(10.0)

    # Look at a column of nodes down the middle. The inflow from uphill should
    # be, from top to bottom: 0, 0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028
    assert_equal(kw.disch_in[85], 0.0)
    assert_equal(round(kw.disch_in[75], 7), 0.0000011)
    assert_equal(round(kw.disch_in[65], 7), 0.0000022)
    assert_equal(round(kw.disch_in[55], 7), 0.0000033)
    assert_equal(round(kw.disch_in[45], 7), 0.0000044)
    assert_equal(round(kw.disch_in[35], 7), 0.0000055)
    assert_equal(round(kw.disch_in[25], 7), 0.0000066)
    assert_equal(round(kw.disch_in[15], 7), 0.0000077)
def test_steady_basic_ramp():
    """Run to steady state with basic ramp"""

    # Create a basic ramp
    rg = RasterModelGrid((10, 10), spacing=(2, 2))
    rg.add_field("topographic__elevation", 0.1 * rg.node_y, at="node")

    # Create component and run it
    kw = KinwaveImplicitOverlandFlow(rg)
    for i in range(12):
        kw.run_one_step(1.0, runoff_rate=0.001)

    # Look at a column of nodes down the middle. The inflow from uphill should
    # be, from top to bottom: 0, 0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028
    assert kw.disch_in[85] == 0.0
    assert round(kw.disch_in[75], 3) == 0.004
    assert round(kw.disch_in[65], 3) == 0.008
    assert round(kw.disch_in[55], 3) == 0.012
    assert round(kw.disch_in[45], 3) == 0.016
    assert round(kw.disch_in[35], 3) == 0.020
    assert round(kw.disch_in[25], 3) == 0.024
    assert round(kw.disch_in[15], 3) == 0.028

    # Try with passing in runoff
    kw = KinwaveImplicitOverlandFlow(rg, runoff_rate=360.0)
    kw.depth[:] = 0.0
    for i in range(22):
        kw.run_one_step(1.0)

    # Again, look at a column of nodes down the middle. The inflow from uphill
    # should now be 1/10 of the prior example.
    assert round(kw.disch_in[75], 4) == 0.0004
    assert round(kw.disch_in[65], 4) == 0.0008
    assert round(kw.disch_in[55], 4) == 0.0012
    assert round(kw.disch_in[45], 4) == 0.0016
    assert round(kw.disch_in[35], 4) == 0.0020
    assert round(kw.disch_in[25], 4) == 0.0024
    assert round(kw.disch_in[15], 4) == 0.0028

    # Try with default runoff rate of 1 mm/hr = 2.78e-7 m/s
    kw = KinwaveImplicitOverlandFlow(rg)
    assert round(kw.runoff_rate * 1.0e7, 2) == 2.78
    kw.depth[:] = 0.0
    for i in range(18):
        kw.run_one_step(10.0)

    # Look at a column of nodes down the middle. The inflow from uphill should
    # be, from top to bottom: 0, 0.004, 0.008, 0.012, 0.016, 0.02, 0.024, 0.028
    assert kw.disch_in[85] == 0.0
    assert round(kw.disch_in[75], 7) == 0.0000011
    assert round(kw.disch_in[65], 7) == 0.0000022
    assert round(kw.disch_in[55], 7) == 0.0000033
    assert round(kw.disch_in[45], 7) == 0.0000044
    assert round(kw.disch_in[35], 7) == 0.0000055
    assert round(kw.disch_in[25], 7) == 0.0000066
    assert round(kw.disch_in[15], 7) == 0.0000077
Exemple #10
0
# +
plt.figure(1)
plt.plot(hydrograph_time, discharge_at_outlet, "r-", label="outlet")

plt.ylabel("Discharge (cms)")
plt.xlabel("Time (hour)")
plt.legend(loc="upper right")
title_text = f"Hydrograph ({dem_path.split('/')[-1].split('.')[0]})"
plt.title(title_text)
plt.show()
# -

# ### Run/Loop Kinematic Wave Overland Flow Component

kw = KinwaveImplicitOverlandFlow(rmg,
                                 runoff_rate=0.0,
                                 roughness=n,
                                 depth_exp=5 / 3)

# +
elapsed_time = 1

while elapsed_time < model_run_time_sec:

    if elapsed_time < storm_duration_sec:
        kw.runoff_rate = starting_precip_mmhr  #This needs to be in mm/hr because the source code automatically converts to m/s
    else:
        kw.runoff_rate = 1e-20  #This needs to be > 0 because of an assertion in the source code...

    kw.run_one_step(dt)

    # add elapsed time to the continuos time
Exemple #11
0
class KinwaveModel(_ErosionModel):
    """
    A DrainageAreaModel simply computes drainage area on a raster-grid DEM.
    """
    
    def __init__(self, input_file=None, params=None):
        """Initialize the LinearDiffusionModel."""
        
        # Call ErosionModel's init
        super(KinwaveModel, self).__init__(input_file=input_file,
                                           params=params)

        # Get input parameters: duration for a runoff (i.e., storm or snowmelt)
        # event, interval of time from the end of one event to the next, and
        # rate of runoff generation (in mm/hr) during an event.
        self.runoff_duration = self.params['runoff__duration']
        self.interstorm_duration = self.params['interstorm__duration']
        self.runoff_rate = self.params['runoff__rate'] / 3.6e6
        
        # A "cycle" is a runoff event plus the interlude before the next event.
        self.cycle_duration = self.runoff_duration + self.interstorm_duration
        
        # Runoff continues for some time after runoff generation ceases. Here
        # we set the amount of time we actively calculate flow. After this
        # time period, we ignore flow for the remainder of the cycle. But if
        # the user-specified hydrograph duration is longer than our cycle, we
        # truncate at the cycle duration, because we'll start computing flow
        # again at the start of the next cycle.
        self.hydrograph_duration = min(self.cycle_duration,
            self.params['hydrograph__maximum_duration'])

        # This variable keeps track of how far we are in one cycle.
        self.current_time_in_cycle = 0.0

        # Instantiate a KinwaveImplicitOverlandFlow
        self.water_router = KinwaveImplicitOverlandFlow(self.grid)


    def run_one_step(self, dt):
        """
        Advance model for one time-step of duration dt.
        """
        self.water_router.run_one_step(dt)


    def run_for(self, dt, runtime):
        """
        Run model without interruption for a specified time period. This
        involves 
        """

        remaining_time = runtime
        remaining_time_in_cycle = (self.cycle_duration
                                   - self.current_time_in_cycle)
        
        while remaining_time > 0.0:

            # If we're in the hydrograph part of the cycle, run a hydrograph.
            if self.current_time_in_cycle < self.hydrograph_duration:
            
                # Set the component's runoff rate according to whether it's
                # still raining or not.
                if self.current_time_in_cycle < self.runoff_duration:
                    self.water_router.runoff_rate = self.runoff_rate
                else:
                    self.water_router.runoff_rate = 0.0

                # Calculate time-step size: we adjust downward from dt if
                # needed to make sure we don't exceed the runoff duration or
                # the runtime.
                delt = min(dt, remaining_time)
                delt = min(delt, self.runoff_duration)

                # Run some water flow
                self.run_one_step(delt)
                
                # Advance time
                remaining_time -= delt
                remaining_time_in_cycle -= delt
                self.current_time_in_cycle += delt

            # If we're in the "dry" part of a cycle, simply advance to either
            # the beginning of the next cycle or the end of the "runtime"
            # period, whichever is shorter.
            else:

                dry_time = min(remaining_time, remaining_time_in_cycle)
                remaining_time -= dry_time
                remaining_time_in_cycle -= dry_time
                if remaining_time_in_cycle > 0.0:
                    self.current_time_in_cycle += dry_time
                else:
                    self.current_time_in_cycle = 0.0  # start a new cycle
                    remaining_time_in_cycle = self.cycle_duration