コード例 #1
0
ファイル: climate.py プロジェクト: terrence1666/oggm
def apparent_mb_from_linear_mb(gdir, mb_gradient=3.):
    """Compute apparent mb from a linear mass-balance assumption (for testing).

    This is for testing currently, but could be used as alternative method
    for the inversion quite easily.

    Parameters
    ----------
    gdir : oggm.GlacierDirectory
    """

    # Do we have a calving glacier?
    cmb = calving_mb(gdir)

    # Get the height and widths along the fls
    h, w = gdir.get_inversion_flowline_hw()

    # Now find the ELA till the integrated mb is zero
    from oggm.core.massbalance import LinearMassBalance

    def to_minimize(ela_h):
        mbmod = LinearMassBalance(ela_h[0], grad=mb_gradient)
        smb = mbmod.get_specific_mb(h, w)
        return (smb - cmb)**2

    ela_h = optimization.minimize(to_minimize, [0.], bounds=((0, 10000), ))
    ela_h = ela_h['x'][0]
    mbmod = LinearMassBalance(ela_h, grad=mb_gradient)

    # For each flowline compute the apparent MB
    fls = gdir.read_pickle('inversion_flowlines')

    # Reset flux
    for fl in fls:
        fl.flux = np.zeros(len(fl.surface_h))

    # Flowlines in order to be sure
    rho = cfg.PARAMS['ice_density']
    for fl in fls:
        mbz = mbmod.get_annual_mb(fl.surface_h) * cfg.SEC_IN_YEAR * rho
        fl.set_apparent_mb(mbz)

    # Check and write
    aflux = fls[-1].flux[-1] * 1e-9 / rho * gdir.grid.dx**2
    # If not marine and a bit far from zero, warning
    if cmb == 0 and not np.allclose(fls[-1].flux[-1], 0., atol=0.01):
        log.warning('(%s) flux should be zero, but is: '
                    '%.4f km3 ice yr-1', gdir.rgi_id, aflux)
    # If not marine and quite far from zero, error
    if cmb == 0 and not np.allclose(fls[-1].flux[-1], 0., atol=1):
        msg = ('({}) flux should be zero, but is: {:.4f} km3 ice yr-1'.format(
            gdir.rgi_id, aflux))
        raise RuntimeError(msg)
    gdir.write_pickle(fls, 'inversion_flowlines')
    gdir.write_pickle({
        'ela_h': ela_h,
        'grad': mb_gradient
    }, 'linear_mb_params')
コード例 #2
0
ファイル: test_chakra.py プロジェクト: ehultee/chakra
def test_water_massbalance():

    mb_mod = LinearMassBalance(ela_h=100, grad=1)
    to_test = mb_mod.get_annual_mb([200, 100, 0, -1, -100])
    # Convert units
    to_test *= cfg.SEC_IN_YEAR * cfg.PARAMS['ice_density']
    # Test
    assert_allclose(to_test, [100, 0, -100, -101, -200])

    mb_mod = WaterMassBalance(ela_h=100, grad=1)
    to_test = mb_mod.get_annual_mb([200, 100, 0, -1, -100])
    # Convert units
    to_test *= cfg.SEC_IN_YEAR * cfg.PARAMS['ice_density']
    # Test
    assert_allclose(to_test, [100, 0, -100, 0, 0])

    mb_mod = WaterMassBalance(ela_h=100, grad=1, underwater_melt=-1000)
    to_test = mb_mod.get_annual_mb([200, 100, 0, -1, -100])
    # Convert units
    to_test *= cfg.SEC_IN_YEAR * cfg.PARAMS['ice_density']
    # Test
    assert_allclose(to_test, [100, 0, -100, -1000, -1000])
コード例 #3
0
    def test_staggered_diagnostics(self):

        mb = LinearMassBalance(2600.)
        fls = dummy_constant_bed()
        model = FluxBasedModel(fls, mb_model=mb, y0=0.)
        model.run_until(700)
        assert_allclose(mb.get_specific_mb(fls=fls), 0, atol=10)

        # Check the flux just for fun
        fl = model.flux_stag[0]
        assert fl[0] == 0

        # Now check the diags
        df = model.get_diagnostics()
        fl = model.fls[0]
        df['my_flux'] = np.cumsum(mb.get_annual_mb(fl.surface_h) *
                                  fl.widths_m * fl.dx_meter *
                                  cfg.SEC_IN_YEAR).clip(0)

        df = df.loc[df['ice_thick'] > 0]

        # Also convert ours
        df['ice_flux'] *= cfg.SEC_IN_YEAR
        df['ice_velocity'] *= cfg.SEC_IN_YEAR
        df['tributary_flux'] *= cfg.SEC_IN_YEAR

        assert_allclose(np.abs(df['ice_flux'] - df['my_flux']), 0, atol=35e3)
        assert df['ice_velocity'].max() > 25
        assert df['tributary_flux'].max() == 0

        fls = dummy_width_bed_tributary()
        model = FluxBasedModel(fls, mb_model=mb, y0=0.)
        model.run_until(500)

        df = model.get_diagnostics()
        df['ice_velocity'] *= cfg.SEC_IN_YEAR
        df['tributary_flux'] *= cfg.SEC_IN_YEAR
        df = df.loc[df['ice_thick'] > 0]
        assert df['ice_velocity'].max() > 50
        assert df['tributary_flux'].max() > 30e4

        df = model.get_diagnostics(fl_id=0)
        df = df.loc[df['ice_thick'] > 0]
        df['ice_velocity'] *= cfg.SEC_IN_YEAR
        df['tributary_flux'] *= cfg.SEC_IN_YEAR
        assert df['ice_velocity'].max() > 10
        assert df['tributary_flux'].max() == 0
コード例 #4
0
 def to_minimize(ela_h):
     mbmod = LinearMassBalance(ela_h[0])
     smb = mbmod.get_annual_mb(heights=topo)
     return np.sum(smb)**2
コード例 #5
0
def gridded_mb_attributes(gdir):
    """Adds mass-balance related attributes to the gridded data file.

    This could be useful for distributed ice thickness models.
    The raster data are added to the gridded_data file.

    Parameters
    ----------
    gdir : :py:class:`oggm.GlacierDirectory`
        where to write the data
    """
    from oggm.core.massbalance import LinearMassBalance, ConstantMassBalance
    from oggm.core.centerlines import line_inflows

    # Get the input data
    with ncDataset(gdir.get_filepath('gridded_data')) as nc:
        topo_2d = nc.variables['topo_smoothed'][:]
        glacier_mask_2d = nc.variables['glacier_mask'][:]
        glacier_mask_2d = glacier_mask_2d == 1
        catchment_mask_2d = glacier_mask_2d * np.NaN

    cls = gdir.read_pickle('centerlines')

    # Catchment areas
    cis = gdir.read_pickle('geometries')['catchment_indices']
    for j, ci in enumerate(cis):
        catchment_mask_2d[tuple(ci.T)] = j

    # Make everything we need flat
    catchment_mask = catchment_mask_2d[glacier_mask_2d].astype(int)
    topo = topo_2d[glacier_mask_2d]

    # Prepare the distributed mass-balance data
    rho = cfg.PARAMS['ice_density']
    dx2 = gdir.grid.dx ** 2

    # Linear
    def to_minimize(ela_h):
        mbmod = LinearMassBalance(ela_h[0])
        smb = mbmod.get_annual_mb(heights=topo)
        return np.sum(smb)**2
    ela_h = optimization.minimize(to_minimize, [0.], method='Powell')
    mbmod = LinearMassBalance(float(ela_h['x']))
    lin_mb_on_z = mbmod.get_annual_mb(heights=topo) * cfg.SEC_IN_YEAR * rho
    if not np.isclose(np.sum(lin_mb_on_z), 0, atol=10):
        raise RuntimeError('Spec mass-balance should be zero but is: {}'
                           .format(np.sum(lin_mb_on_z)))

    # Normal OGGM (a bit tweaked)
    df = gdir.read_json('local_mustar')

    def to_minimize(mu_star):
        mbmod = ConstantMassBalance(gdir, mu_star=mu_star, bias=0,
                                    check_calib_params=False,
                                    y0=df['t_star'])
        smb = mbmod.get_annual_mb(heights=topo)
        return np.sum(smb)**2
    mu_star = optimization.minimize(to_minimize, [0.], method='Powell')
    mbmod = ConstantMassBalance(gdir, mu_star=float(mu_star['x']), bias=0,
                                check_calib_params=False,
                                y0=df['t_star'])
    oggm_mb_on_z = mbmod.get_annual_mb(heights=topo) * cfg.SEC_IN_YEAR * rho
    if not np.isclose(np.sum(oggm_mb_on_z), 0, atol=10):
        raise RuntimeError('Spec mass-balance should be zero but is: {}'
                           .format(np.sum(oggm_mb_on_z)))

    # Altitude based mass balance
    catch_area_above_z = topo * np.NaN
    lin_mb_above_z = topo * np.NaN
    oggm_mb_above_z = topo * np.NaN
    for i, h in enumerate(topo):
        catch_area_above_z[i] = np.sum(topo >= h) * dx2
        lin_mb_above_z[i] = np.sum(lin_mb_on_z[topo >= h]) * dx2
        oggm_mb_above_z[i] = np.sum(oggm_mb_on_z[topo >= h]) * dx2

    # Hardest part - MB per catchment
    catchment_area = topo * np.NaN
    lin_mb_above_z_on_catch = topo * np.NaN
    oggm_mb_above_z_on_catch = topo * np.NaN

    # First, find all inflows indices and min altitude per catchment
    inflows = []
    lowest_h = []
    for i, cl in enumerate(cls):
        lowest_h.append(np.min(topo[catchment_mask == i]))
        inflows.append([cls.index(l) for l in line_inflows(cl, keep=False)])

    for i, (catch_id, h) in enumerate(zip(catchment_mask, topo)):

        if h == np.min(topo):
            t = 1

        # Find the catchment area of the point itself by eliminating points
        # below the point altitude. We assume we keep all of them first,
        # then remove those we don't want
        sel_catchs = inflows[catch_id].copy()
        for catch in inflows[catch_id]:
            if h >= lowest_h[catch]:
                for cc in np.append(inflows[catch], catch):
                    try:
                        sel_catchs.remove(cc)
                    except ValueError:
                        pass

        # At the very least we need or own catchment
        sel_catchs.append(catch_id)

        # Then select all the catchment points
        sel_points = np.isin(catchment_mask, sel_catchs)

        # And keep the ones above our altitude
        sel_points = sel_points & (topo >= h)

        # Compute
        lin_mb_above_z_on_catch[i] = np.sum(lin_mb_on_z[sel_points]) * dx2
        oggm_mb_above_z_on_catch[i] = np.sum(oggm_mb_on_z[sel_points]) * dx2
        catchment_area[i] = np.sum(sel_points) * dx2

    # Make 2D again
    def _fill_2d_like(data):
        out = topo_2d * np.NaN
        out[glacier_mask_2d] = data
        return out

    catchment_area = _fill_2d_like(catchment_area)
    catch_area_above_z = _fill_2d_like(catch_area_above_z)
    lin_mb_above_z = _fill_2d_like(lin_mb_above_z)
    oggm_mb_above_z = _fill_2d_like(oggm_mb_above_z)
    lin_mb_above_z_on_catch = _fill_2d_like(lin_mb_above_z_on_catch)
    oggm_mb_above_z_on_catch = _fill_2d_like(oggm_mb_above_z_on_catch)

    # Save to file
    with ncDataset(gdir.get_filepath('gridded_data'), 'a') as nc:

        vn = 'catchment_area'
        if vn in nc.variables:
            v = nc.variables[vn]
        else:
            v = nc.createVariable(vn, 'f4', ('y', 'x', ))
        v.units = 'm^2'
        v.long_name = 'Catchment area above point'
        v.description = ('This is a very crude method: just the area above '
                         'the points elevation on glacier.')
        v[:] = catch_area_above_z

        vn = 'catchment_area_on_catch'
        if vn in nc.variables:
            v = nc.variables[vn]
        else:
            v = nc.createVariable(vn, 'f4', ('y', 'x',))
        v.units = 'm^2'
        v.long_name = 'Catchment area above point on flowline catchments'
        v.description = ('Uses the catchments masks of the flowlines to '
                         'compute the area above the altitude of the given '
                         'point.')
        v[:] = catchment_area

        vn = 'lin_mb_above_z'
        if vn in nc.variables:
            v = nc.variables[vn]
        else:
            v = nc.createVariable(vn, 'f4', ('y', 'x', ))
        v.units = 'kg/year'
        v.long_name = 'MB above point from linear MB model, without catchments'
        v.description = ('Mass-balance cumulated above the altitude of the'
                         'point, hence in unit of flux. Note that it is '
                         'a coarse approximation of the real flux. '
                         'The mass-balance model is a simple linear function'
                         'of altitude.')
        v[:] = lin_mb_above_z

        vn = 'lin_mb_above_z_on_catch'
        if vn in nc.variables:
            v = nc.variables[vn]
        else:
            v = nc.createVariable(vn, 'f4', ('y', 'x', ))
        v.units = 'kg/year'
        v.long_name = 'MB above point from linear MB model, with catchments'
        v.description = ('Mass-balance cumulated above the altitude of the'
                         'point in a flowline catchment, hence in unit of '
                         'flux. Note that it is a coarse approximation of the '
                         'real flux. The mass-balance model is a simple '
                         'linear function of altitude.')
        v[:] = lin_mb_above_z_on_catch

        vn = 'oggm_mb_above_z'
        if vn in nc.variables:
            v = nc.variables[vn]
        else:
            v = nc.createVariable(vn, 'f4', ('y', 'x', ))
        v.units = 'kg/year'
        v.long_name = 'MB above point from OGGM MB model, without catchments'
        v.description = ('Mass-balance cumulated above the altitude of the'
                         'point, hence in unit of flux. Note that it is '
                         'a coarse approximation of the real flux. '
                         'The mass-balance model is a calibrated temperature '
                         'index model like OGGM.')
        v[:] = oggm_mb_above_z

        vn = 'oggm_mb_above_z_on_catch'
        if vn in nc.variables:
            v = nc.variables[vn]
        else:
            v = nc.createVariable(vn, 'f4', ('y', 'x', ))
        v.units = 'kg/year'
        v.long_name = 'MB above point from OGGM MB model, with catchments'
        v.description = ('Mass-balance cumulated above the altitude of the'
                         'point in a flowline catchment, hence in unit of '
                         'flux. Note that it is a coarse approximation of the '
                         'real flux. The mass-balance model is a calibrated '
                         'temperature index model like OGGM.')
        v[:] = oggm_mb_above_z_on_catch