Source code for umami.calculations.residual.kstest

import numpy as np
from scipy.stats import ks_2samp

from landlab.utils import get_watershed_mask


[docs]def kstest(model_grid, data_grid, field): """Calculate an Kolmogorov-Smirnov test for a Landlab grid field. ``kstest`` calculates the Kolmogorov-Smirnov test for goodness of fit using the function ``ks_2samp`` from ``scipy.stats``. Parameters ---------- model_grid : Landlab model grid data_grid : Landlab model grid field : str An at-node Landlab grid field that is present on both grids. Returns ------- out : float The KS test statistic Examples -------- First an example that only uses the ``kstest`` function. >>> import numpy as np >>> from landlab import RasterModelGrid >>> from umami.calculations import kstest >>> np.random.seed(42) >>> model = RasterModelGrid((10, 10)) >>> z_model = model.add_zeros("node", "topographic__elevation") >>> z_model += model.x_of_node + model.y_of_node >>> data = RasterModelGrid((10, 10)) >>> z_data = data.add_zeros("node", "topographic__elevation") >>> z_data += data.x_of_node + data.y_of_node >>> z_data[data.core_nodes] += np.random.random(data.core_nodes.shape) >>> np.round(kstest(model, data, "topographic__elevation"), decimals=3) 0.125 Next, the same calculations are shown as part of an umami ``Residual``. >>> from io import StringIO >>> from umami import Residual >>> file_like=StringIO(''' ... ks: ... _func: kstest ... field: topographic__elevation ... ''') >>> residual = Residual(model, data) >>> residual.add_from_file(file_like) >>> residual.names ['ks'] >>> residual.calculate() >>> residual.values [0.125] """ model_vals = model_grid.at_node[field][model_grid.core_nodes] data_vals = data_grid.at_node[field][data_grid.core_nodes] d, _ = ks_2samp(model_vals, data_vals) return d
[docs]def kstest_watershed(model_grid, data_grid, field, outlet_id): """Calculate an Kolmogorov-Smirnov test for a watershed. ``kstest_watershed`` calculates the Kolmogorov-Smirnov test for goodness of fit using the function ``ks_2samp`` from ``scipy.stats``. Given an *outlet_id* it identifes a watershed mask for the *data_grid*. It then uses that mask on both the *data_grid* and the *model_grid*. If the field is "flow__distance", then this performs a KS test of the width function. Parameters ---------- model_grid : Landlab model grid data_grid : Landlab model grid field : str An at-node Landlab grid field that is present on both grids. outlet_id : int Returns ------- out : float The KS test statistic Examples -------- First an example that only uses the ``kstest`` function. >>> import numpy as np >>> from landlab import RasterModelGrid >>> from landlab.components import FlowAccumulator >>> from umami.calculations import kstest_watershed >>> np.random.seed(42) >>> model = RasterModelGrid((10, 10)) >>> z_model = model.add_zeros("node", "topographic__elevation") >>> z_model += model.x_of_node + model.y_of_node >>> data = RasterModelGrid((10, 10)) >>> z_data = data.add_zeros("node", "topographic__elevation") >>> z_data += data.x_of_node + data.y_of_node >>> z_data[data.core_nodes] += np.random.random(data.core_nodes.shape) >>> data_fa = FlowAccumulator(data) >>> data_fa.run_one_step() >>> model_fa = FlowAccumulator(model) >>> model_fa.run_one_step() >>> np.round( ... kstest_watershed( ... model, ... data, ... "topographic__elevation", ... outlet_id=1), ... decimals=3) 0.5 Next, the same calculations are shown as part of an umami ``Residual``. >>> from io import StringIO >>> from umami import Residual >>> file_like=StringIO(''' ... ksw: ... _func: kstest_watershed ... outlet_id: 1 ... field: topographic__elevation ... ''') >>> residual = Residual(model, data) >>> residual.add_from_file(file_like) >>> residual.names ['ksw'] >>> residual.calculate() >>> np.round(residual.values, decimals=3) array([ 0.5]) """ mask = get_watershed_mask(data_grid, outlet_id) model_vals = model_grid.at_node[field][mask] data_vals = data_grid.at_node[field][mask] d, _ = ks_2samp(model_vals, data_vals) return d