def test_interp_2d_to_3d():
    grid = np.array([
        [18.0, 15.0],
        [14.0, 13.0],
        [12.0, 10.0],
    ])
    gt = (30.0, 20.0, 0.0, 130.0, 0.0, -20.0)
    # Test points within
    x = np.tile(np.arange(30, 80, 10), 7)
    y = np.repeat(np.arange(70, 140, 10)[::-1], 5)
    expected_z = [
        18.0, 18.0, 16.5, 15.0, 15.0, 18.0, 18.0, 16.5, 15.0, 15.0, 16.0, 16.0,
        15.0, 14.0, 14.0, 14.0, 14.0, 13.5, 13.0, 13.0, 13.0, 13.0, 12.25,
        11.5, 11.5, 12.0, 12.0, 11.0, 10.0, 10.0, 12.0, 12.0, 11.0, 10.0, 10.0
    ]
    gs2d = geopandas.GeoSeries([Point(xy) for xy in zip(x, y)])
    gs3d = spatial.interp_2d_to_3d(gs2d, grid, gt)
    np.testing.assert_array_equal(gs3d.apply(lambda g: g.z), expected_z)
    # plt.imshow(np.array(expected_z).reshape((7, 5)))
    # plt.imshow(grid)
    # Test inside corners
    x_in = [30, 70, 70, 30]
    y_in = [130, 130, 70, 70]
    gs3d = spatial.interp_2d_to_3d(
        geopandas.GeoSeries([Point(xy) for xy in zip(x_in, y_in)]), grid, gt)
    np.testing.assert_array_equal(gs3d.apply(lambda g: g.z), [18, 15, 10, 12])
    # Points outside shoud raise an exception
    x_out = [29, 71, 71, 29]
    y_out = [131, 131, 69, 69]
    outside_combs = list(zip(x_out, y_out)) + list(zip(x_in, y_out)) + \
        list(zip(x_out, y_in))
    for pt in outside_combs:
        with pytest.raises(ValueError, match='coordinates are outside grid'):
            spatial.interp_2d_to_3d(geopandas.GeoSeries([Point(pt)]), grid, gt)
def test_pickle(tmp_path):
    sim, m = get_basic_modflow(tmp_path, with_top=True)
    gt = swn.modflow.geotransform_from_flopy(m)
    lsz = interp_2d_to_3d(n3d_lines, m.dis.top.array, gt)
    n = swn.SurfaceWaterNetwork.from_lines(lsz)
    n.adjust_elevation_profile()
    nm1 = swn.SwnMf6.from_swn_flopy(n, m)
    # use pickle dumps / loads methods
    data = pickle.dumps(nm1)
    nm2 = pickle.loads(data)
    assert nm1 != nm2
    assert nm2.swn is None
    assert nm2.model is None
    nm2.swn = n
    nm2.model = m
    assert nm1 == nm2
    # use to_pickle / from_pickle methods
    diversions = geopandas.GeoDataFrame(
        geometry=[Point(58, 97),
                  Point(62, 97),
                  Point(61, 89),
                  Point(59, 89)])
    n.set_diversions(diversions=diversions)
    nm3 = swn.SwnMf6.from_swn_flopy(n, m)
    nm3.to_pickle(tmp_path / "nm4.pickle")
    nm4 = swn.SwnMf6.from_pickle(tmp_path / "nm4.pickle", n, m)
    assert nm3 == nm4

    # Issue 31
    with pytest.raises(TypeError, match="swn property must be an instance o"):
        swn.SwnMf6.from_pickle(tmp_path / "nm4.pickle", m)
    with pytest.raises(AttributeError, match="swn property can only be set o"):
        nm2.swn = n
def test_diversions():
    m = get_basic_modflow(with_top=True)
    gt = swn.modflow.geotransform_from_flopy(m)
    assert gt == (30.0, 20.0, 0.0, 130.0, 0.0, -20.0)
    # Interpolate the line from the top of the model
    lsz = interp_2d_to_3d(n3d_lines, m.dis.top.array, gt)
    n = swn.SurfaceWaterNetwork.from_lines(lsz)
    diversions = geopandas.GeoDataFrame(
        geometry=[Point(58, 97),
                  Point(62, 97),
                  Point(61, 89),
                  Point(59, 89)])
    n.set_diversions(diversions=diversions)
    n.adjust_elevation_profile()
    nm = swn.SwnModflow.from_swn_flopy(n, m)

    # Check dataframes
    assert len(nm.reaches) == 11
    assert len(np.unique(nm.reaches.iseg)) == 7
    assert len(nm.diversions) == 4
    assert nm.diversions["in_model"].sum() == 4
    assert len(nm.segments) == 3
    assert nm.segments["in_model"].sum() == 3

    # Check reaches
    assert list(nm.reaches.index) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
    assert list(nm.reaches.segnum) == [1, 1, 1, 2, 2, 0, 0, -1, -1, -1, -1]
    # Base-0
    assert list(nm.reaches.k) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    assert list(nm.reaches.i) == [0, 0, 1, 0, 1, 1, 2, 1, 1, 2, 2]
    assert list(nm.reaches.j) == [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    # Base-1
    assert list(nm.reaches.iseg) == [1, 1, 1, 2, 2, 3, 3, 4, 5, 6, 7]
    assert list(nm.reaches.ireach) == [1, 2, 3, 1, 2, 1, 2, 1, 1, 1, 1]

    # Other data
    np.testing.assert_array_almost_equal(nm.reaches.segndist, [
        0.25, 0.58333333, 0.8333333333, 0.333333333, 0.833333333, 0.25, 0.75,
        0.0, 0.0, 0.0, 0.0
    ])
    np.testing.assert_array_almost_equal(nm.reaches.rchlen, [
        18.027756, 6.009252, 12.018504, 21.081852, 10.540926, 10.0, 10.0, 1.0,
        1.0, 1.0, 1.0
    ])

    assert "slope" not in nm.reaches.columns
    nm.set_reach_slope("auto", 0.001)
    np.testing.assert_array_almost_equal(nm.reaches.slope, [
        0.02861207, 0.02861207, 0.02861207, 0.001, 0.001, 0.04841886,
        0.04841886, 0.001, 0.001, 0.001, 0.001
    ])

    assert repr(nm) == dedent("""\
        <SwnModflow: flopy mf2005 'modflowtest'
          11 in reaches (reachID): [1, 2, ..., 10, 11]
          1 stress period with perlen: [1.0] />""")
    if matplotlib:
        _ = nm.plot()
        plt.close()
def test_diversions(tmp_path):
    sim, m = get_basic_modflow(tmp_path, with_top=True)
    gt = swn.modflow.geotransform_from_flopy(m)
    lsz = interp_2d_to_3d(n3d_lines, m.dis.top.array, gt)
    n = swn.SurfaceWaterNetwork.from_lines(lsz)
    n.adjust_elevation_profile()
    diversions = geopandas.GeoDataFrame(
        geometry=[Point(58, 97),
                  Point(62, 97),
                  Point(61, 89),
                  Point(59, 89)])
    n.set_diversions(diversions=diversions)

    # With zero specified flow for all terms
    nm = swn.SwnMf6.from_swn_flopy(n, m, hyd_cond1=0.0)
    del nm
def test_geotransform_from_flopy():
    m = get_basic_modflow(with_top=True)
    gt = swn.modflow.geotransform_from_flopy(m)
    assert gt == (30.0, 20.0, 0.0, 130.0, 0.0, -20.0)
    # Interpolate the line from the top of the model
    lsz = interp_2d_to_3d(n3d_lines, m.dis.top.array, gt)
    n = swn.SurfaceWaterNetwork.from_lines(lsz)
    n.adjust_elevation_profile()
    nm = swn.SwnModflow.from_swn_flopy(n, m)
    nm.set_reach_slope()
    np.testing.assert_array_almost_equal(
        nm.reaches.zcoord_avg,  # aka strtop or rtop
        [
            15.742094, 15.39822, 15.140314, 14.989459, 14.973648, 14.726283,
            14.242094
        ])
    np.testing.assert_array_almost_equal(nm.reaches.slope, [
        0.02861207, 0.02861207, 0.02861207, 0.001, 0.001, 0.04841886,
        0.04841886
    ])