Exemplo n.º 1
0
    def D_value(phi, ele, tra_to_cut, cmask, drmask_not):
        # Some inputs are in fipy CellVariable type
        gwt = phi.value * cmask.value - ele

        d = hydro_utils.peat_map_h_to_tra(
            soil_type_mask=peat_type_mask, gwt=gwt,
            h_to_tra_and_C_dict=httd) - tra_to_cut

        # d <0 means tra_to_cut is greater than the other transmissivity, which in turn means that
        # phi is below the impermeable bottom. We allow phi to have those values, but
        # the transmissivity is in those points is equal to zero (as if phi was exactly at the impermeable bottom).
        d[d < 0] = 1e-3  # Small non-zero value not to wreck the computation

        dcell = fp.CellVariable(
            mesh=mesh, value=d
        )  # diffusion coefficient, transmissivity. As a cell variable.
        dface = fp.FaceVariable(mesh=mesh,
                                value=dcell.arithmeticFaceValue.value
                                )  # THe correct Face variable.

        return dface.value
Exemplo n.º 2
0
# after peeling, catchment_mask should only be the fruit:
catchment_mask[boundary_mask] = False

# soil types and soil physical properties and soil depth:
peat_type_masked = peat_type_arr * catchment_mask
peat_bottom_elevation = -peat_depth_arr * catchment_mask  # meters with respect to dem surface. Should be negative!

h_to_tra_and_C_dict, K = hydro_utils.peat_map_interp_functions(
    KADJUST)  # Load peatmap soil types' physical properties dictionary
#soiltypes[soiltypes==255] = 0 # 255 is nodata value. 1 is water (useful for hydrology! Maybe, same treatment as canals).

#BOTTOM_ELE = -6.0
#peat_bottom_elevation = np.ones(shape=dem.shape) * BOTTOM_ELE
#peat_bottom_elevation = peat_bottom_elevation*catchment_mask
tra_to_cut = hydro_utils.peat_map_h_to_tra(
    soil_type_mask=peat_type_masked,
    gwt=peat_bottom_elevation,
    h_to_tra_and_C_dict=h_to_tra_and_C_dict)
sto_to_cut = hydro_utils.peat_map_h_to_sto(
    soil_type_mask=peat_type_masked,
    gwt=peat_bottom_elevation,
    h_to_tra_and_C_dict=h_to_tra_and_C_dict)
sto_to_cut = sto_to_cut * catchment_mask.ravel()

srfcanlist = [dem[coords] for coords in c_to_r_list]

n_canals = len(c_to_r_list)

# HANDCRAFTED WATER LEVEL IN CANALS. CHANGE WITH MEASURED, IDEALLY.

oWTcanlist = [x - CANAL_WATER_LEVEL for x in srfcanlist]
"""
Exemplo n.º 3
0
def hydrology(solve_mode,
              nx,
              ny,
              dx,
              dy,
              days,
              ele,
              phi_initial,
              catchment_mask,
              wt_canal_arr,
              boundary_arr,
              peat_type_mask,
              httd,
              tra_to_cut,
              sto_to_cut,
              diri_bc=0.0,
              neumann_bc=None,
              plotOpt=False,
              remove_ponding_water=True,
              P=0.0,
              ET=0.0,
              dt=1.0):
    """
    INPUT:
        - ele: (nx,ny) sized NumPy array. Elevation in m above c.r.p.
        - Hinitial: (nx,ny) sized NumPy array. Initial water table in m above c.r.p.
        - catchment mask: (nx,ny) sized NumPy array. Boolean array = True where the node is inside the computation area. False if outside.
        - wt_can_arr: (nx,ny) sized NumPy array. Zero everywhere except in nodes that contain canals, where = wl of the canal.
        - value_for_masked: DEPRECATED. IT IS NOW THE SAME AS diri_bc.
        - diri_bc: None or float. If None, Dirichlet BC will not be implemented. If float, this number will be the BC.
        - neumann_bc: None or float. If None, Neumann BC will not be implemented. If float, this is the value of grad phi.
        - P: Float. Constant precipitation. mm/day.
        - ET: Float. Constant evapotranspiration. mm/day.
    """
    #    dneg = []

    track_WT_drained_area = (239, 166)
    track_WT_notdrained_area = (522, 190)

    ele[~catchment_mask] = 0.
    ele = ele.flatten()
    phi_initial = (phi_initial + 0.0 * np.zeros((ny, nx))) * catchment_mask
    #    phi_initial = phi_initial * catchment_mask
    phi_initial = phi_initial.flatten()

    if len(ele) != nx * ny or len(phi_initial) != nx * ny:
        raise ValueError("ele or Hinitial are not of dim nx*ny")

    mesh = fp.Grid2D(dx=dx, dy=dy, nx=nx, ny=ny)
    phi = fp.CellVariable(
        name='computed H', mesh=mesh, value=phi_initial,
        hasOld=True)  #response variable H in meters above reference level

    if diri_bc != None and neumann_bc == None:
        phi.constrain(diri_bc, mesh.exteriorFaces)

    elif diri_bc == None and neumann_bc != None:
        phi.faceGrad.constrain(neumann_bc * mesh.faceNormals,
                               where=mesh.exteriorFaces)

    else:
        raise ValueError(
            "Cannot apply Dirichlet and Neumann boundary values at the same time. Contradictory values."
        )

    #*******omit areas outside the catchment. c is input
    cmask = fp.CellVariable(mesh=mesh, value=np.ravel(catchment_mask))
    cmask_not = fp.CellVariable(mesh=mesh,
                                value=np.array(~cmask.value, dtype=int))

    # *** drain mask or canal mask
    dr = np.array(wt_canal_arr, dtype=bool)
    dr[np.array(wt_canal_arr, dtype=bool) * np.array(
        boundary_arr, dtype=bool
    )] = False  # Pixels cannot be canals and boundaries at the same time. Everytime a conflict appears, boundaries win. This overwrites any canal water level info if the canal is in the boundary.
    drmask = fp.CellVariable(mesh=mesh, value=np.ravel(dr))
    drmask_not = fp.CellVariable(
        mesh=mesh, value=np.array(~drmask.value, dtype=int)
    )  # Complementary of the drains mask, but with ints {0,1}

    # mask away unnecesary stuff
    #    phi.setValue(np.ravel(H)*cmask.value)
    #    ele = ele * cmask.value

    source = fp.CellVariable(mesh=mesh,
                             value=0.)  # cell variable for source/sink

    #    CC=fp.CellVariable(mesh=mesh, value=C(phi.value-ele))                   # differential water capacity

    def D_value(phi, ele, tra_to_cut, cmask, drmask_not):
        # Some inputs are in fipy CellVariable type
        gwt = phi.value * cmask.value - ele

        d = hydro_utils.peat_map_h_to_tra(
            soil_type_mask=peat_type_mask, gwt=gwt,
            h_to_tra_and_C_dict=httd) - tra_to_cut

        # d <0 means tra_to_cut is greater than the other transmissivity, which in turn means that
        # phi is below the impermeable bottom. We allow phi to have those values, but
        # the transmissivity is in those points is equal to zero (as if phi was exactly at the impermeable bottom).
        d[d < 0] = 1e-3  # Small non-zero value not to wreck the computation

        dcell = fp.CellVariable(
            mesh=mesh, value=d
        )  # diffusion coefficient, transmissivity. As a cell variable.
        dface = fp.FaceVariable(mesh=mesh,
                                value=dcell.arithmeticFaceValue.value
                                )  # THe correct Face variable.

        return dface.value

    def C_value(phi, ele, sto_to_cut, cmask, drmask_not):
        # Some inputs are in fipy CellVariable type
        gwt = phi.value * cmask.value - ele

        c = hydro_utils.peat_map_h_to_sto(
            soil_type_mask=peat_type_mask, gwt=gwt,
            h_to_tra_and_C_dict=httd) - sto_to_cut
        c[c < 0] = 1e-3  # Same reasons as for D

        ccell = fp.CellVariable(
            mesh=mesh, value=c
        )  # diffusion coefficient, transmissivity. As a cell variable.
        return ccell.value

    D = fp.FaceVariable(
        mesh=mesh, value=D_value(phi, ele, tra_to_cut, cmask,
                                 drmask_not))  # THe correct Face variable.
    C = fp.CellVariable(
        mesh=mesh, value=C_value(phi, ele, sto_to_cut, cmask,
                                 drmask_not))  # differential water capacity

    largeValue = 1e20  # value needed in implicit source term to apply internal boundaries

    if plotOpt:
        big_4_raster_plot(
            title='Before the computation',
            raster1=(
                (hydro_utils.peat_map_h_to_tra(soil_type_mask=peat_type_mask,
                                               gwt=(phi.value - ele),
                                               h_to_tra_and_C_dict=httd) -
                 tra_to_cut) * cmask.value * drmask_not.value).reshape(ny, nx),
            raster2=(ele.reshape(ny, nx) - wt_canal_arr) * dr * catchment_mask,
            raster3=ele.reshape(ny, nx),
            raster4=(ele - phi.value).reshape(ny, nx))
        # for later cross-section plots
        y_value = 270

#        print "first cross-section plot"
#        ele_with_can = copy.copy(ele).reshape(ny,nx)
#        ele_with_can = ele_with_can * catchment_mask
#        ele_with_can[wt_canal_arr > 0] = wt_canal_arr[wt_canal_arr > 0]
#        plot_line_of_peat(ele_with_can, y_value=y_value, title="cross-section", color='green', nx=nx, ny=ny, label="ele")

# ********************************** PDE, STEADY STATE **********************************
    if solve_mode == 'steadystate':
        if diri_bc != None:
            #        diri_boundary = fp.CellVariable(mesh=mesh, value= np.ravel(diri_boundary_value(boundary_mask, ele2d, diri_bc)))

            eq = 0. == (
                fp.DiffusionTerm(coeff=D) + source * cmask * drmask_not -
                fp.ImplicitSourceTerm(cmask_not * largeValue) +
                cmask_not * largeValue * np.ravel(boundary_arr) -
                fp.ImplicitSourceTerm(drmask * largeValue) +
                drmask * largeValue * (np.ravel(wt_canal_arr))
                #                    - fp.ImplicitSourceTerm(bmask_not*largeValue) + bmask_not*largeValue*(boundary_arr)
            )

        elif neumann_bc != None:
            raise NotImplementedError("Neumann BC not implemented yet!")
            cmask_face = fp.FaceVariable(mesh=mesh,
                                         value=np.array(
                                             cmask.arithmeticFaceValue.value,
                                             dtype=bool))
            D[cmask_face.value] = 0.
            eq = 0. == (
                fp.DiffusionTerm(coeff=D) + source * cmask * drmask_not -
                fp.ImplicitSourceTerm(cmask_not * largeValue) +
                cmask_not * largeValue * (diri_bc) -
                fp.ImplicitSourceTerm(drmask * largeValue) +
                drmask * largeValue * (np.ravel(wt_canal_arr))
                #                + fp.DiffusionTerm(coeff=largeValue * bmask_face)
                #                - fp.ImplicitSourceTerm((bmask_face * largeValue *neumann_bc * mesh.faceNormals).divergence)
            )

    elif solve_mode == 'transient':
        if diri_bc != None:
            #        diri_boundary = fp.CellVariable(mesh=mesh, value= np.ravel(diri_boundary_value(boundary_mask, ele2d, diri_bc)))

            eq = fp.TransientTerm(coeff=C) == (
                fp.DiffusionTerm(coeff=D) + source * cmask * drmask_not -
                fp.ImplicitSourceTerm(cmask_not * largeValue) +
                cmask_not * largeValue * np.ravel(boundary_arr) -
                fp.ImplicitSourceTerm(drmask * largeValue) +
                drmask * largeValue * (np.ravel(wt_canal_arr))
                #                        - fp.ImplicitSourceTerm(bmask_not*largeValue) + bmask_not*largeValue*(boundary_arr)
            )
        elif neumann_bc != None:
            raise NotImplementedError("Neumann BC not implemented yet!")

    #********************************************************

    max_sweeps = 10  # inner loop.

    avg_wt = []
    wt_track_drained = []
    wt_track_notdrained = []

    cumulative_Vdp = 0.

    #********Finite volume computation******************
    for d in range(days):
        source.setValue(
            (P[d] - ET[d]) * .001 * np.ones(ny * nx)
        )  # source/sink. P and ET are in mm/day. The factor of 10^-3 converst to m/day. It does not matter that there are 100 x 100 m^2 in one pixel
        print("(d, P - ET) = ", (d, (P[d] - ET[d])))
        if plotOpt and d != 0:
            # print "one more cross-section plot"
            plot_line_of_peat(phi.value.reshape(ny, nx),
                              y_value=y_value,
                              title="cross-section",
                              color='cornflowerblue',
                              nx=nx,
                              ny=ny,
                              label=d)

        res = 0.0

        phi.updateOld()

        D.setValue(D_value(phi, ele, tra_to_cut, cmask, drmask_not))
        C.setValue(C_value(phi, ele, tra_to_cut, cmask, drmask_not))

        for r in range(max_sweeps):
            resOld = res

            res = eq.sweep(var=phi, dt=dt)  # solve linearization of PDE

            #print "sum of Ds: ", np.sum(D.value)/1e8
            #print "average wt: ", np.average(phi.value-ele)

            #print 'residue diference:    ', res - resOld

            if abs(res - resOld) < 1e-7:
                break  # it has reached to the solution of the linear system

        if solve_mode == 'transient':  #solving in steadystate will remove water only at the very end
            if remove_ponding_water:
                s = np.where(
                    phi.value > ele, ele, phi.value
                )  # remove the surface water. This also removes phi in those masked values (for the plot only)
                phi.setValue(s)  # set new values for water table

        if (D.value < 0.).any():
            print("Some value in D is negative!")

        # For some plots
        avg_wt.append(np.average(phi.value - ele))
        wt_track_drained.append(
            (phi.value - ele).reshape(ny, nx)[track_WT_drained_area])
        wt_track_notdrained.append(
            (phi.value - ele).reshape(ny, nx)[track_WT_notdrained_area])
        """ Volume of dry peat calc."""
        not_peat = np.ones(shape=peat_type_mask.shape)  # Not all soil is peat!
        not_peat[peat_type_mask == 4] = 0  # NotPeat
        not_peat[peat_type_mask == 5] = 0  # OpenWater
        peat_vol_weights = utilities.PeatV_weight_calc(
            np.array(~dr * catchment_mask * not_peat, dtype=int))
        dry_peat_volume = utilities.PeatVolume(peat_vol_weights,
                                               (ele - phi.value).reshape(
                                                   ny, nx))
        cumulative_Vdp = cumulative_Vdp + dry_peat_volume
        print("avg_wt  = ", np.average(phi.value - ele))
        #        print "wt drained = ", (phi.value - ele).reshape(ny,nx)[track_WT_drained_area]
        #        print "wt not drained = ", (phi.value - ele).reshape(ny,nx)[track_WT_notdrained_area]
        print("Cumulative vdp = ", cumulative_Vdp)

    if solve_mode == 'steadystate':  #solving in steadystate we remove water only at the very end
        if remove_ponding_water:
            s = np.where(
                phi.value > ele, ele, phi.value
            )  # remove the surface water. This also removes phi in those masked values (for the plot only)
            phi.setValue(s)  # set new values for water table

        # Areas with WT <-1.0; areas with WT >0
#        plot_raster_by_value((ele-phi.value).reshape(ny,nx), title="ele-phi in the end, colour keys", bottom_value=0.5, top_value=0.01)

    if plotOpt:
        big_4_raster_plot(
            title='After the computation',
            raster1=(
                (hydro_utils.peat_map_h_to_tra(soil_type_mask=peat_type_mask,
                                               gwt=(phi.value - ele),
                                               h_to_tra_and_C_dict=httd) -
                 tra_to_cut) * cmask.value * drmask_not.value).reshape(ny, nx),
            raster2=(ele.reshape(ny, nx) - wt_canal_arr) * dr * catchment_mask,
            raster3=ele.reshape(ny, nx),
            raster4=(ele - phi.value).reshape(ny, nx))

        fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12, 9), dpi=80)
        x = np.arange(-21, 1, 0.1)
        axes[0, 0].plot(httd[1]['hToTra'](x), x)
        axes[0, 0].set(title='hToTra', ylabel='depth')
        axes[0, 1].plot(httd[1]['C'](x), x)
        axes[0, 1].set(title='C')
        axes[1, 0].plot()
        axes[1, 0].set(title="Nothing")
        axes[1, 1].plot(avg_wt)
        axes[1, 1].set(title="avg_wt_over_time")

        # plot surface in cross-section
        ele_with_can = copy.copy(ele).reshape(ny, nx)
        ele_with_can = ele_with_can * catchment_mask
        ele_with_can[wt_canal_arr > 0] = wt_canal_arr[wt_canal_arr > 0]
        plot_line_of_peat(ele_with_can,
                          y_value=y_value,
                          title="cross-section",
                          nx=nx,
                          ny=ny,
                          label="surface",
                          color='peru',
                          linewidth=2.0)

        plt.show()

#    change_in_canals = (ele-phi.value).reshape(ny,nx)*(drmask.value.reshape(ny,nx)) - ((ele-H)*drmask.value).reshape(ny,nx)
#    resulting_phi = phi.value.reshape(ny,nx)

    phi.updateOld()

    return (phi.value - ele).reshape(ny, nx)