Example #1
0
def get_local_speed(states: States, gravity: float) -> States:
    """Calculate local speeds on the two sides of cell faces.

    Arguments
    ---------
    states : torchswe.utils.data.States
    gravity : float
        Gravity in m / s^2.

    Returns
    -------
    states : torchswe.utils.data.States
        The same object as the input. Changed inplace. Returning it just for coding style.
    """

    # faces normal to x-direction
    sqrt_gh_plus = nplike.sqrt(gravity * states.face.x.plus.h)
    sqrt_gh_minus = nplike.sqrt(gravity * states.face.x.minus.h)

    # for convenience
    zero = nplike.array(0.)

    states.face.x.plus.a = nplike.maximum(
        nplike.maximum(states.face.x.plus.u + sqrt_gh_plus,
                       states.face.x.minus.u + sqrt_gh_minus), zero)

    states.face.x.minus.a = nplike.minimum(
        nplike.minimum(states.face.x.plus.u - sqrt_gh_plus,
                       states.face.x.minus.u - sqrt_gh_minus), zero)

    # faces normal to y-direction
    sqrt_gh_plus = nplike.sqrt(gravity * states.face.y.plus.h)
    sqrt_gh_minus = nplike.sqrt(gravity * states.face.y.minus.h)

    states.face.y.plus.a = nplike.maximum(
        nplike.maximum(states.face.y.plus.v + sqrt_gh_plus,
                       states.face.y.minus.v + sqrt_gh_minus), zero)

    states.face.y.minus.a = nplike.minimum(
        nplike.minimum(states.face.y.plus.v - sqrt_gh_plus,
                       states.face.y.minus.v - sqrt_gh_minus), zero)

    return states
Example #2
0
def minmod_slope_x_one_comp(q: nplike.ndarray, dx: float, ngh: int,
                            theta: float, tol: float):
    """Minmod slope in x direction for only one conservative quantity (Legate version).

    Arguments
    ---------
    q : nplike.ndarray
        (ny+2*ngh, nx+2*ngh) array of a conservative quantity.
    dx : float
        Cell size in x-direction. Assume an uniform grid.
    ngh : int
        Number of ghost cell layers outside each boundary.
    theta: float
        Parameter to controll oscillation and dispassion. 1 <= theta <= 2.
    tol : float
        To control how small can be treat as zero.

    Returns
    -------
    slpx : nplike.ndarray
        (ny, nx+2) array of the slopes in x-direction, including one ghost layer at west and east.
    """
    # pylint: disable=invalid-name

    cells = slice(ngh, -ngh)  # non-ghost cells, length ny or nx
    i = slice(ngh - 1, q.shape[1] - ngh +
              1)  # i = one ghost outside each bound; length nx+2
    ip1 = slice(ngh, q.shape[1] - ngh + 2)  # i + 1; length nx+2
    im1 = slice(ngh - 2, q.shape[1] - ngh)  # i - 1; length nx+2

    denominator = q[cells, ip1] - q[cells,
                                    i]  # q_{j, i+1} - q_{j, i} for all j

    # legate currently has no `logical_and`, so we use element-wise multiplication
    zero_locs = (denominator > -tol).astype(int) * (denominator <
                                                    tol).astype(int)

    with nplike.errstate(divide="ignore", invalid="ignore"):
        slpx = nplike.where(zero_locs.astype(bool), 0.,
                            (q[cells, i] - q[cells, im1]) / denominator)

    slpx = nplike.maximum(
        nplike.minimum(nplike.minimum(theta * slpx, (1. + slpx) / 2.), theta),
        0.)

    slpx *= denominator
    slpx /= dx

    return slpx
Example #3
0
def minmod_slope_y_one_comp(q: nplike.ndarray, dy: float, ngh: int,
                            theta: float, tol: float):
    """Minmod slope in x direction for only one conservative quantity.

    Arguments
    ---------
    q : nplike.ndarray
        (ny+2*ngh, nx+2*ngh) array of a conservative quantity.
    dy : float
        Cell size in y-direction. Assume an uniform grid.
    ngh : int
        Number of ghost cell layers outside each boundary.
    theta: float
        Parameter to controll oscillation and dispassion. 1 <= theta <= 2.
    tol : float
        To control how small can be treat as zero.

    Returns
    -------
    slpy : nplike.ndarray
        (ny+2, nx) array of the slopes in y-direction, including one ghost layer at west and east.
    """
    # pylint: disable=invalid-name

    cells = slice(ngh, -ngh)  # non-ghost cells, length ny or nx
    j = slice(ngh - 1, q.shape[0] - ngh +
              1)  # j = one ghost outside each bound; length ny+2
    jp1 = slice(ngh, q.shape[0] - ngh + 2)  # j + 1; length ny+2
    jm1 = slice(ngh - 2, q.shape[0] - ngh)  # j - 1; length ny+2

    denominator = q[jp1, cells] - q[j,
                                    cells]  # q_{j+1, i} - q_{j, i} for all i
    zeros = nplike.nonzero(
        nplike.logical_and(denominator > -tol, denominator < tol))

    with nplike.errstate(divide="ignore", invalid="ignore"):
        slpy = (q[j, cells] - q[jm1, cells]) / denominator

    slpy[zeros] = 0.  # where q_{j+1, i} - q_{j, i} = 0

    slpy = nplike.maximum(
        nplike.minimum(nplike.minimum(theta * slpy, (1. + slpy) / 2.),
                       nplike.array(theta)), nplike.array(0.))

    slpy *= denominator
    slpy /= dy

    return slpy
Example #4
0
def create_ic(comm, ic_config, grid, topo, dtype):
    """Create initial conditions.

    When the x_cntr and y_cntr have different resolutions from the x and y in the NetCDF file, an
    bi-cubic spline interpolation will take place.

    Arguments
    ---------
    comm : mpi4py.MPI.Comm
        The communicator.
    ic_config : torchswe.utils.config.ICConfig
    grid : torchswe.utils.data.Gridlines
    topo : torchswe.utils.data.Topography
    dtype : str; either "float32" or "float64"

    Returns
    -------
    torchswe.utils.data.WHUHVModel
    """

    # special case: constant I.C.
    if ic_config.values is not None:
        return _WHUHVModel(nx=grid.x.n,
                           ny=grid.y.n,
                           dtype=dtype,
                           w=_nplike.maximum(
                               topo.cntr, _nplike.array(ic_config.values[0])),
                           hu=_nplike.full(topo.cntr.shape,
                                           ic_config.values[1],
                                           dtype=topo.dtype),
                           hv=_nplike.full(topo.cntr.shape,
                                           ic_config.values[2],
                                           dtype=topo.dtype))

    # otherwise, read data from a NetCDF file
    icdata, _ = _ncread(
        ic_config.file,
        ic_config.keys,
        [grid.x.cntr[0], grid.x.cntr[-1], grid.y.cntr[0], grid.y.cntr[-1]],
        parallel=True,
        comm=comm)

    # see if we need to do interpolation
    try:
        interp = not (_nplike.allclose(grid.x.cntr, icdata["x"])
                      and _nplike.allclose(grid.y.cntr, icdata["y"]))
    except ValueError:  # assume thie excpetion means a shape mismatch
        interp = True

    # unfortunately, we need to do interpolation in such a situation
    if interp:
        _logger.warning("Grids do not match. Doing spline interpolation.")
        w = _nplike.array(
            _interpolate(icdata["x"], icdata["y"], icdata[ic_config.keys[0]].T,
                         grid.x.cntr, grid.y.cntr).T)

        hu = _nplike.array(
            _interpolate(icdata["x"], icdata["y"], icdata[ic_config.keys[1]].T,
                         grid.x.cntr, grid.y.cntr).T)

        hv = _nplike.array(
            _interpolate(icdata["x"], icdata["y"], icdata[ic_config.keys[2]].T,
                         grid.x.cntr, grid.y.cntr).T)
    else:
        w = icdata[ic_config.keys[0]]
        hu = icdata[ic_config.keys[1]]
        hv = icdata[ic_config.keys[2]]

    # make sure the w can not be smaller than topopgraphy elevation
    w = _nplike.maximum(w, topo.cntr)

    return _WHUHVModel(nx=grid.x.n,
                       ny=grid.y.n,
                       dtype=dtype,
                       w=w,
                       hu=hu,
                       hv=hv)
Example #5
0
 def get_uv(h, hu, hv):
     # pylint: disable=invalid-name
     h4 = nplike.power(h, 4)
     coeff = h * sqrt2 / nplike.sqrt(
         h4 + nplike.maximum(h4, nplike.array(epsilon)))
     return coeff * hu, coeff * hv
Example #6
0
def fvm(states: States, grid: Gridlines, topo: Topography, config: Config, runtime: DummyDict):
    """Get the right-hand-side of a time-marching step with finite volume method.

    Arguments
    ---------
    states : torchswe.utils.data.States
    grid : torchswe.utils.data.Gridlines
    topo : torchswe.utils.data.Topography
    config : torchswe.utils.config.Config
    runtime : torchswe.utils.dummy.DummyDict

    Returns:
    --------
    states : torchswe.utils.data.States
        The same object as the input. Updated in-place. Returning it just for coding style.
    max_dt : float
        A scalar indicating the maximum safe time-step size.
    """
    # pylint: disable=invalid-name

    # calculate source term contributed from topography gradients
    states = topography_gradient(states, topo, config.params.gravity)

    # calculate slopes of piecewise linear approximation
    states = minmod_slope(states, grid, config.params.theta, runtime.tol)

    # interpolate to get discontinuous conservative quantities at cell faces
    states = get_discontinuous_cnsrv_q(states, grid)

    # fix non-physical negative depth
    states = correct_negative_depth(states, topo)

    # get non-conservative variables at cell faces
    states = decompose_variables(states, topo, runtime.epsilon)

    # get local speed at cell faces
    states = get_local_speed(states, config.params.gravity)

    # get discontinuous PDE flux at cell faces
    states = get_discontinuous_flux(states, topo, config.params.gravity)

    # get common/continuous numerical flux at cell faces
    states = central_scheme(states, runtime.tol)

    # get final right hand side
    states.rhs.w = \
        (states.face.x.num_flux.w[:, :-1] - states.face.x.num_flux.w[:, 1:]) / grid.x.delta + \
        (states.face.y.num_flux.w[:-1, :] - states.face.y.num_flux.w[1:, :]) / grid.y.delta + \
        states.src.w

    states.rhs.hu = \
        (states.face.x.num_flux.hu[:, :-1] - states.face.x.num_flux.hu[:, 1:]) / grid.x.delta + \
        (states.face.y.num_flux.hu[:-1, :] - states.face.y.num_flux.hu[1:, :]) / grid.y.delta + \
        states.src.hu

    states.rhs.hv = \
        (states.face.x.num_flux.hv[:, :-1] - states.face.x.num_flux.hv[:, 1:]) / grid.x.delta + \
        (states.face.y.num_flux.hv[:-1, :] - states.face.y.num_flux.hv[1:, :]) / grid.y.delta + \
        states.src.hv

    # remove rounding errors
    states.rhs = remove_rounding_errors(states.rhs, runtime.tol)

    # obtain the maximum safe dt
    amax = nplike.max(nplike.maximum(states.face.x.plus.a, -states.face.x.minus.a))
    bmax = nplike.max(nplike.maximum(states.face.y.plus.a, -states.face.y.minus.a))
    max_dt = min(0.25*grid.x.delta/amax, 0.25*grid.y.delta/bmax)

    return states, max_dt
Example #7
0
 def inflow_bc_velocity(conserv_q):
     depth = nplike.maximum(conserv_q[w_idx] - topo_cache[bcslc], 0.)
     delta = (const * depth - conserv_q[anchor]) * 2
     conserv_q[slc] = conserv_q[anchor] + seq * delta
     return conserv_q
Example #8
0
def create_ic(ic_config, gridlines, topo, dtype):
    """Create initial conditions.

    When the x_cntr and y_cntr have different resolutions from the x and y in the NetCDF file, an
    bi-cubic spline interpolation will take place.

    Arguments
    ---------
    ic_config : torchswe.utils.config.ICConfig
    gridlines : torchswe.utils.data.Gridlines
    topo : torchswe.utils.data.Topography
    dtype : str; either "float32" or "float64"

    Returns
    -------
    torchswe.utils.data.WHUHVModel
    """

    # special case: constant I.C.
    if ic_config.values is not None:
        return WHUHVModel(gridlines.x.n,
                          gridlines.y.n,
                          dtype,
                          w=nplike.maximum(topo.cntr,
                                           nplike.array(ic_config.values[0])),
                          hu=nplike.full(topo.cntr.shape,
                                         ic_config.values[1],
                                         dtype=topo.dtype),
                          hv=nplike.full(topo.cntr.shape,
                                         ic_config.values[2],
                                         dtype=topo.dtype))

    # otherwise, read data from a NetCDF file
    icdata, _ = read_cf(ic_config.file, ic_config.keys)

    # see if we need to do interpolation
    try:
        interp = not (
            nplike.allclose(gridlines.x.cntr, nplike.array(icdata["x"]))
            and nplike.allclose(gridlines.y.cntr, nplike.array(icdata["y"])))
    except ValueError:  # assume thie excpetion means a shape mismatch
        interp = True

    # unfortunately, we need to do interpolation in such a situation
    if interp:
        interpolator = RectBivariateSpline(icdata["x"], icdata["y"],
                                           icdata[ic_config.keys[0]][:].T)
        w = interpolator(gridlines.x.cntr, gridlines.y.cntr).T

        # get an interpolator for conserv_q_ic[1], use the default 3rd order spline
        interpolator = RectBivariateSpline(icdata["x"], icdata["y"],
                                           icdata[ic_config.keys[1]][:].T)
        hu = interpolator(gridlines.x.cntr, gridlines.y.cntr).T

        # get an interpolator for conserv_q_ic[2], use the default 3rd order spline
        interpolator = RectBivariateSpline(icdata["x"], icdata["y"],
                                           icdata[ic_config.keys[2]][:].T)
        hv = interpolator(gridlines.x.cntr, gridlines.y.cntr).T
    else:
        w = nplike.array(icdata[ic_config.keys[0]][:].copy())
        hu = nplike.array(icdata[ic_config.keys[1]][:].copy())
        hv = nplike.array(icdata[ic_config.keys[2]][:].copy())

    # make sure the w can not be smaller than topopgraphy elevation
    w = nplike.maximum(w, topo.cntr)

    return WHUHVModel(gridlines.x.n, gridlines.y.n, dtype, w=w, hu=hu, hv=hv)