Esempio n. 1
0
    def test_point_snapping_break_ties(self):
        """DelineateIt: distance ties are broken using flow accumulation."""
        from natcap.invest.delineateit import delineateit

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(32731)  # WGS84/UTM zone 31s
        wkt = srs.ExportToWkt()

        # need stream layer, points
        stream_matrix = numpy.array(
            [[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0]],
            dtype=numpy.int8)
        stream_raster_path = os.path.join(self.workspace_dir, 'streams.tif')
        flow_accum_array = numpy.array(
            [[1, 5, 1, 1, 1, 1], [1, 5, 1, 1, 1, 1], [1, 5, 1, 1, 1, 1],
             [1, 5, 1, 1, 1, 1], [1, 5, 9, 9, 9, 9], [1, 4, 1, 1, 1, 1],
             [1, 4, 1, 1, 1, 1]],
            dtype=numpy.int8)
        flow_accum_path = os.path.join(self.workspace_dir, 'flow_accum.tif')
        pygeoprocessing.numpy_array_to_raster(stream_matrix, 255, (2, -2),
                                              (2, -2), wkt, stream_raster_path)
        pygeoprocessing.numpy_array_to_raster(flow_accum_array, -1, (2, -2),
                                              (2, -2), wkt, flow_accum_path)

        source_points_path = os.path.join(self.workspace_dir,
                                          'source_features.geojson')
        source_features = [Point(9, -7)]  # equidistant from two streams
        pygeoprocessing.shapely_geometry_to_vector(
            source_features,
            source_points_path,
            wkt,
            'GeoJSON',
            ogr_geom_type=ogr.wkbUnknown)

        snapped_points_path = os.path.join(self.workspace_dir,
                                           'snapped_points.gpkg')

        snap_distance = 10  # large enough to get multiple streams per point.
        delineateit.snap_points_to_nearest_stream(source_points_path,
                                                  stream_raster_path,
                                                  flow_accum_path,
                                                  snap_distance,
                                                  snapped_points_path)

        snapped_points_vector = gdal.OpenEx(snapped_points_path,
                                            gdal.OF_VECTOR)
        snapped_points_layer = snapped_points_vector.GetLayer()

        # should snap to stream point [4, 3] in the array above
        # if not considering flow accumulation, it would snap to the
        # nearest stream point found first in the array, at [2, 1]
        points = [
            shapely.wkb.loads(bytes(feature.GetGeometryRef().ExportToWkb()))
            for feature in snapped_points_layer
        ]
        self.assertEqual(len(points), 1)
        self.assertEqual((points[0].x, points[0].y), (9, -11))
Esempio n. 2
0
    def test_clip_vector_by_vector_no_intersection(self):
        """WaveEnergy: testing '_clip_vector_by_vector' w/ no intersection."""
        from natcap.invest import wave_energy

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(3157)
        projection_wkt = srs.ExportToWkt()
        origin = (443723.127327877911739, 4956546.905980412848294)
        pos_x = origin[0]
        pos_y = origin[1]

        fields_pt = {'id': ogr.OFTInteger, 'myattr': ogr.OFTString}
        attrs_one = [{'id': 1, 'myattr': 'hello'}]

        fields_poly = {'id': ogr.OFTInteger}
        attrs_poly = [{'id': 1}]
        # Create geometry for the points, which will get clipped
        geom_one = [Point(pos_x + 220, pos_y - 220)]
        # Create geometry for the polygons, which will be used to clip
        geom_two = [
            Polygon([(pos_x, pos_y), (pos_x + 60, pos_y),
                     (pos_x + 60, pos_y - 60), (pos_x, pos_y - 60),
                     (pos_x, pos_y)])
        ]

        shape_to_clip_path = os.path.join(self.workspace_dir,
                                          'shape_to_clip.shp')
        # Create the point shapefile
        pygeoprocessing.shapely_geometry_to_vector(geom_one,
                                                   shape_to_clip_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields_pt,
                                                   attribute_list=attrs_one,
                                                   ogr_geom_type=ogr.wkbPoint)

        binding_shape_path = os.path.join(self.workspace_dir,
                                          'binding_shape.shp')
        # Create the polygon shapefile
        pygeoprocessing.shapely_geometry_to_vector(geom_two,
                                                   binding_shape_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields_poly,
                                                   attribute_list=attrs_poly)

        output_path = os.path.join(self.workspace_dir, 'vector.shp')
        # Call the function to test
        self.assertRaises(wave_energy.IntersectionError,
                          wave_energy._clip_vector_by_vector,
                          shape_to_clip_path, binding_shape_path, output_path,
                          projection_wkt, self.workspace_dir)
Esempio n. 3
0
    def test_calculate_distances_land_grid(self):
        """WindEnergy: testing 'calculate_distances_land_grid' function."""
        from natcap.invest import wind_energy

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(3157)
        projection_wkt = srs.ExportToWkt()
        origin = (443723.127327877911739, 4956546.905980412848294)
        pos_x = origin[0]
        pos_y = origin[1]

        # Setup parameters for creating point shapefile
        fields = {'id': ogr.OFTReal, 'L2G': ogr.OFTReal}
        attrs = [{'id': 1, 'L2G': 10}, {'id': 2, 'L2G': 20}]

        geometries = [
            Point(pos_x + 50, pos_y - 50),
            Point(pos_x + 50, pos_y - 150)
        ]
        land_shape_path = os.path.join(self.workspace_dir, 'temp_shape.shp')
        # Create point shapefile to use for testing input
        pygeoprocessing.shapely_geometry_to_vector(geometries,
                                                   land_shape_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields,
                                                   attribute_list=attrs,
                                                   ogr_geom_type=ogr.wkbPoint)

        # Setup parameters for create raster
        matrix = numpy.array([[1, 1, 1, 1], [1, 1, 1, 1]], dtype=numpy.int32)
        harvested_masked_path = os.path.join(self.workspace_dir,
                                             'temp_raster.tif')
        # Create raster to use for testing input
        pygeoprocessing.numpy_array_to_raster(matrix, -1, (100, -100), origin,
                                              projection_wkt,
                                              harvested_masked_path)

        tmp_dist_final_path = os.path.join(self.workspace_dir,
                                           'dist_final.tif')
        # Call function to test given testing inputs
        wind_energy._calculate_distances_land_grid(land_shape_path,
                                                   harvested_masked_path,
                                                   tmp_dist_final_path, '')

        # Compare the results
        res_array = pygeoprocessing.raster_to_numpy_array(tmp_dist_final_path)
        exp_array = numpy.array([[10, 110, 210, 310], [20, 120, 220, 320]],
                                dtype=numpy.int32)
        numpy.testing.assert_allclose(res_array, exp_array)
Esempio n. 4
0
    def test_create_distance_raster(self):
        """WindEnergy: testing '_create_distance_raster' function."""
        from natcap.invest import wind_energy

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(3157)  #UTM Zone 10N
        projection_wkt = srs.ExportToWkt()
        origin = (443723.127327877911739, 4956546.905980412848294)
        pos_x = origin[0]
        pos_y = origin[1]

        # Setup and create vector to pass to function
        fields = {'id': ogr.OFTReal}
        attrs = [{'id': 1}]

        # Square polygon that will overlap the 4 pixels of the raster in the
        # upper left corner
        poly_geometry = [box(pos_x, pos_y - 17, pos_x + 17, pos_y)]
        poly_vector_path = os.path.join(self.workspace_dir,
                                        'distance_from_vector.gpkg')
        # Create polygon shapefile to use as testing input
        pygeoprocessing.shapely_geometry_to_vector(
            poly_geometry,
            poly_vector_path,
            projection_wkt,
            'GPKG',
            fields=fields,
            attribute_list=attrs,
            ogr_geom_type=ogr.wkbPolygon)

        # Create 2x5 raster
        matrix = numpy.array([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1]],
                             dtype=numpy.float32)
        base_raster_path = os.path.join(self.workspace_dir, 'temp_raster.tif')
        # Create raster to use for testing input
        pygeoprocessing.numpy_array_to_raster(matrix, -1, (10, -10), origin,
                                              projection_wkt, base_raster_path)

        dist_raster_path = os.path.join(self.workspace_dir, 'dist.tif')
        # Call function to test given testing inputs
        wind_energy._create_distance_raster(base_raster_path, poly_vector_path,
                                            dist_raster_path,
                                            self.workspace_dir)

        # Compare the results
        res_array = pygeoprocessing.raster_to_numpy_array(dist_raster_path)
        exp_array = numpy.array([[0, 0, 10, 20, 30], [0, 0, 10, 20, 30]],
                                dtype=numpy.float32)
        numpy.testing.assert_allclose(res_array, exp_array)
Esempio n. 5
0
    def test_pollination_bad_farm_type(self):
        """Pollination: ensure detection of bad farm geometry type."""
        from natcap.invest import pollination

        # make some fake farm points
        point_geom = [shapely.geometry.Point(20, -20)]

        farm_shape_path = os.path.join(self.workspace_dir, 'point_farm.shp')
        # Create the point shapefile
        srs = osr.SpatialReference()
        srs.ImportFromEPSG(3157)
        projection_wkt = srs.ExportToWkt()

        fields = {
            'crop_type': ogr.OFTString,
            'half_sat': ogr.OFTReal,
            'p_managed': ogr.OFTReal
        }
        attrs = [{'crop_type': 'test', 'half_sat': 0.5, 'p_managed': 0.5}]

        pygeoprocessing.shapely_geometry_to_vector(point_geom,
                                                   farm_shape_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields,
                                                   attribute_list=attrs,
                                                   ogr_geom_type=ogr.wkbPoint)

        args = {
            'results_suffix':
            '',
            'workspace_dir':
            self.workspace_dir,
            'landcover_raster_path':
            os.path.join(REGRESSION_DATA, 'input', 'clipped_landcover.tif'),
            'guild_table_path':
            os.path.join(REGRESSION_DATA, 'input', 'guild_table.csv'),
            'landcover_biophysical_table_path':
            os.path.join(REGRESSION_DATA, 'input',
                         'landcover_biophysical_table.csv'),
            'farm_vector_path':
            farm_shape_path,
        }
        with self.assertRaises(ValueError):
            pollination.execute(args)
Esempio n. 6
0
    def test_simplify_geometry_lines(self):
        """HRA: test _simplify_geometry does not alter geometry given lines."""
        from natcap.invest.hra import _simplify_geometry
        from natcap.invest.utils import _assert_vectors_equal

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(EPSG_CODE)
        projection_wkt = srs.ExportToWkt()
        base_lines_path = os.path.join(self.workspace_dir, 'base_lines.gpkg')
        lines = [LineString([(0.0, 0.0), (10.0, 10.0)])]
        pygeoprocessing.shapely_geometry_to_vector(
            lines, base_lines_path, projection_wkt, 'GPKG',
            ogr_geom_type=ogr.wkbLineString)

        target_simplified_vector_path = os.path.join(
            self.workspace_dir, 'simplified_vector.gpkg')

        tolerance = 3000  # in meters
        _simplify_geometry(
            base_lines_path, tolerance, target_simplified_vector_path)

        _assert_vectors_equal(
            target_simplified_vector_path, base_lines_path)
Esempio n. 7
0
    def test_point_snapping(self):
        """DelineateIt: test point snapping."""
        from natcap.invest.delineateit import delineateit

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(32731)  # WGS84/UTM zone 31s
        wkt = srs.ExportToWkt()

        # need stream layer, points
        stream_matrix = numpy.array(
            [[0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1], [0, 1, 0, 0, 0, 0],
             [0, 1, 0, 0, 0, 0]],
            dtype=numpy.int8)
        stream_raster_path = os.path.join(self.workspace_dir, 'streams.tif')
        # byte datatype
        pygeoprocessing.numpy_array_to_raster(stream_matrix, 255, (2, -2),
                                              (2, -2), wkt, stream_raster_path)

        source_points_path = os.path.join(self.workspace_dir,
                                          'source_features.geojson')
        source_features = [
            Point(-1, -1),  # off the edge of the stream raster.
            Point(3, -5),
            Point(7, -9),
            Point(13, -5),
            MultiPoint([(13, -5)]),
            box(-2, -2, -1, -1),  # Off the edge
        ]
        fields = {'foo': ogr.OFTInteger, 'bar': ogr.OFTString}
        attributes = [
            {
                'foo': 0,
                'bar': '0.1'
            },
            {
                'foo': 1,
                'bar': '1.1'
            },
            {
                'foo': 2,
                'bar': '2.1'
            },
            {
                'foo': 3,
                'bar': '3.1'
            },
            {
                'foo': 3,
                'bar': '3.1'
            },  # intentional duplicate fields
            {
                'foo': 4,
                'bar': '4.1'
            }
        ]
        pygeoprocessing.shapely_geometry_to_vector(
            source_features,
            source_points_path,
            wkt,
            'GeoJSON',
            fields=fields,
            attribute_list=attributes,
            ogr_geom_type=ogr.wkbUnknown)

        snapped_points_path = os.path.join(self.workspace_dir,
                                           'snapped_points.gpkg')

        snap_distance = -1
        with self.assertRaises(ValueError) as cm:
            delineateit.snap_points_to_nearest_stream(source_points_path,
                                                      (stream_raster_path, 1),
                                                      snap_distance,
                                                      snapped_points_path)
        self.assertTrue('must be >= 0' in str(cm.exception))

        snap_distance = 10  # large enough to get multiple streams per point.
        delineateit.snap_points_to_nearest_stream(source_points_path,
                                                  (stream_raster_path, 1),
                                                  snap_distance,
                                                  snapped_points_path)

        snapped_points_vector = gdal.OpenEx(snapped_points_path,
                                            gdal.OF_VECTOR)
        snapped_points_layer = snapped_points_vector.GetLayer()

        # snapped layer will include 4 valid points and 1 polygon.
        self.assertEqual(5, snapped_points_layer.GetFeatureCount())

        expected_geometries_and_fields = [
            (Point(5, -5), {
                'foo': 1,
                'bar': '1.1'
            }),
            (Point(5, -9), {
                'foo': 2,
                'bar': '2.1'
            }),
            (Point(13, -11), {
                'foo': 3,
                'bar': '3.1'
            }),
            (Point(13, -11), {
                'foo': 3,
                'bar': '3.1'
            }),  # Multipoint now point
            (box(-2, -2, -1, -1), {
                'foo': 4,
                'bar': '4.1'
            }),  # unchanged
        ]
        for feature, (expected_geom,
                      expected_fields) in zip(snapped_points_layer,
                                              expected_geometries_and_fields):
            shapely_feature = shapely.wkb.loads(
                bytes(feature.GetGeometryRef().ExportToWkb()))

            self.assertTrue(shapely_feature.equals(expected_geom))
            self.assertEqual(expected_fields, feature.items())
Esempio n. 8
0
    def test_bounding_boxes(self):
        """Usage logger test that we can extract bounding boxes."""
        from natcap.invest import utils
        from natcap.invest.ui import usage

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(32731)  # WGS84 / UTM zone 31s
        srs_wkt = srs.ExportToWkt()

        raster_path = os.path.join(self.workspace_dir, 'raster.tif')
        driver = gdal.GetDriverByName('GTiff')
        raster_array = numpy.ones((20, 20))
        raster = driver.Create(raster_path,
                               raster_array.shape[1],
                               raster_array.shape[0],
                               1,
                               gdal.GDT_Byte,
                               options=('TILED=YES', 'BIGTIFF=YES',
                                        'COMPRESS=LZW', 'BLOCKXSIZE=256',
                                        'BLOCKYSIZE=256'))
        raster.SetProjection(srs_wkt)
        raster_band = raster.GetRasterBand(1)
        raster_band.WriteArray(raster_array)
        raster_band.SetNoDataValue(255)
        raster_geotransform = [2, 2, 0, -2, 0, -2]
        raster.SetGeoTransform(raster_geotransform)
        raster = None

        vector_path = os.path.join(self.workspace_dir, 'vector.gpkg')
        pygeoprocessing.shapely_geometry_to_vector(
            [shapely.geometry.LineString([(4, -4), (10, -10)])],
            vector_path,
            srs_wkt,
            "GPKG",
            ogr_geom_type=ogr.wkbLineString)

        model_args = {
            'raster': raster_path,
            'vector': vector_path,
            'not_a_gis_input': 'foobar'
        }

        args_spec = {
            'args': {
                'raster': {
                    'type': 'raster'
                },
                'vector': {
                    'type': 'vector'
                },
                'not_a_gis_input': {
                    'type': 'freestyle_string'
                }
            }
        }

        output_logfile = os.path.join(self.workspace_dir, 'logfile.txt')
        with utils.log_to_file(output_logfile):
            bb_inter, bb_union = usage._calculate_args_bounding_box(
                model_args, args_spec)

        numpy.testing.assert_allclose(
            bb_inter, [-87.234108, -85.526151, -87.233424, -85.526205])
        numpy.testing.assert_allclose(
            bb_union, [-87.237771, -85.526132, -87.23321, -85.526491])

        # Verify that no errors were raised in calculating the bounding boxes.
        self.assertTrue('ERROR' not in open(output_logfile).read(),
                        'Exception logged when there should not have been.')
Esempio n. 9
0
    def test_clip_vector_by_vector_points(self):
        """WaveEnergy: testing clipping points from polygons."""
        from natcap.invest import wave_energy

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(3157)
        projection_wkt = srs.ExportToWkt()
        origin = (443723.127327877911739, 4956546.905980412848294)
        pos_x = origin[0]
        pos_y = origin[1]

        fields_pt = {'id': ogr.OFTInteger, 'myattr': ogr.OFTString}
        attrs_one = [{
            'id': 1,
            'myattr': 'hello'
        }, {
            'id': 2,
            'myattr': 'bye'
        }, {
            'id': 3,
            'myattr': 'highbye'
        }]

        fields_poly = {'id': ogr.OFTInteger}
        attrs_poly = [{'id': 1}]
        # Create geometry for the points, which will get clipped
        geom_one = [
            Point(pos_x + 20, pos_y - 20),
            Point(pos_x + 40, pos_y - 20),
            Point(pos_x + 100, pos_y - 20)
        ]
        # Create geometry for the polygons, which will be used to clip
        geom_two = [
            Polygon([(pos_x, pos_y), (pos_x + 60, pos_y),
                     (pos_x + 60, pos_y - 60), (pos_x, pos_y - 60),
                     (pos_x, pos_y)])
        ]

        shape_to_clip_path = os.path.join(self.workspace_dir,
                                          'shape_to_clip.shp')
        # Create the point shapefile
        pygeoprocessing.shapely_geometry_to_vector(geom_one,
                                                   shape_to_clip_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields_pt,
                                                   attribute_list=attrs_one,
                                                   ogr_geom_type=ogr.wkbPoint)

        binding_shape_path = os.path.join(self.workspace_dir,
                                          'binding_shape.shp')
        # Create the polygon shapefile
        pygeoprocessing.shapely_geometry_to_vector(geom_two,
                                                   binding_shape_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields_poly,
                                                   attribute_list=attrs_poly)

        output_path = os.path.join(self.workspace_dir, 'vector.shp')
        # Call the function to test
        wave_energy._clip_vector_by_vector(shape_to_clip_path,
                                           binding_shape_path, output_path,
                                           projection_wkt, self.workspace_dir)

        # Create the expected point shapefile
        fields_pt = {'id': ogr.OFTInteger, 'myattr': ogr.OFTString}
        attrs_one = [{'id': 1, 'myattr': 'hello'}, {'id': 2, 'myattr': 'bye'}]
        geom_three = [
            Point(pos_x + 20, pos_y - 20),
            Point(pos_x + 40, pos_y - 20)
        ]
        # Need to save the expected shapefile in a sub folder since it must
        # have the same layer name / filename as what it will be compared
        # against.
        if not os.path.isdir(os.path.join(self.workspace_dir, 'exp_vector')):
            os.mkdir(os.path.join(self.workspace_dir, 'exp_vector'))

        expected_path = os.path.join(self.workspace_dir, 'exp_vector',
                                     'vector.shp')
        pygeoprocessing.shapely_geometry_to_vector(geom_three,
                                                   expected_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields_pt,
                                                   attribute_list=attrs_one,
                                                   ogr_geom_type=ogr.wkbPoint)

        WaveEnergyRegressionTests._assert_point_vectors_equal(
            output_path, expected_path)
Esempio n. 10
0
    def test_watersheds_diagnostic_vector(self):
        """PGP watersheds: test diagnostic vector."""
        flow_dir_array = numpy.array(
            [[6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6],
             [6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [6, 6, 6, 6, 6, 6, 6, 6, 6, 255],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 2, 2, 2, 2, 2, 2, 2, 2, 255],
             [2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
             [2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]],
            dtype=numpy.int8)

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(32731)  # WGS84 / UTM zone 31s
        srs_wkt = srs.ExportToWkt()

        flow_dir_path = os.path.join(self.workspace_dir, 'flow_dir.tif')
        pygeoprocessing.numpy_array_to_raster(base_array=flow_dir_array,
                                              target_nodata=255,
                                              pixel_size=(2, -2),
                                              origin=(2, -2),
                                              projection_wkt=srs_wkt,
                                              target_path=flow_dir_path)

        # These geometries test:
        #  * Delineation works with varying geometry types
        #  * That we exclude seed pixels that are over nodata
        #  * That we exclude seed pixels off the bounds of the raster
        horizontal_line = shapely.geometry.LineString([(19, -11), (25, -11)])
        vertical_line = shapely.geometry.LineString([(21, -9), (21, -13)])
        square = shapely.geometry.box(17, -13, 21, -9)
        point = shapely.geometry.Point(21, -11)

        outflow_vector_path = os.path.join(self.workspace_dir, 'outflow.gpkg')
        pygeoprocessing.shapely_geometry_to_vector(
            [horizontal_line, vertical_line, square, point],
            outflow_vector_path,
            srs_wkt,
            'GPKG', {
                'polygon_id': ogr.OFTInteger,
                'field_string': ogr.OFTString,
                'other': ogr.OFTReal
            }, [{
                'polygon_id': 1,
                'field_string': 'hello world',
                'other': 1.111
            }, {
                'polygon_id': 2,
                'field_string': 'hello foo',
                'other': 2.222
            }, {
                'polygon_id': 3,
                'field_string': 'hello bar',
                'other': 3.333
            }, {
                'polygon_id': 4,
                'field_string': 'hello baz',
                'other': 4.444
            }],
            ogr_geom_type=ogr.wkbUnknown)

        target_watersheds_path = os.path.join(self.workspace_dir,
                                              'watersheds.gpkg')

        pygeoprocessing.routing.delineate_watersheds_d8(
            (flow_dir_path, 1),
            outflow_vector_path,
            target_watersheds_path,
            write_diagnostic_vector=True,
            working_dir=self.workspace_dir,
            remove_temp_files=False)

        # I'm deliberately only testing that the diagnostic files exist, not
        # the contents.  The diagnostic files should be for debugging only,
        # so I just want to make sure that they're created.
        num_diagnostic_files = len(
            glob.glob(os.path.join(self.workspace_dir, '**/*_seeds.gpkg')))
        self.assertEqual(num_diagnostic_files, 3)  # 3 features valid
Esempio n. 11
0
    def test_watersheds_trivial(self):
        """PGP watersheds: test trivial delineation."""
        flow_dir_array = numpy.array(
            [[6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [6, 6, 6, 6, 6, 6, 6, 6, 6, 6],
             [6, 6, 6, 6, 6, 6, 6, 6, 6, 6], [6, 6, 6, 6, 6, 6, 6, 6, 6, 255],
             [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [2, 2, 2, 2, 2, 2, 2, 2, 2, 255],
             [2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2],
             [2, 2, 2, 2, 2, 2, 2, 2, 2, 2], [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]],
            dtype=numpy.int8)

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(32731)  # WGS84 / UTM zone 31s
        srs_wkt = srs.ExportToWkt()

        flow_dir_path = os.path.join(self.workspace_dir, 'flow_dir.tif')
        pygeoprocessing.numpy_array_to_raster(base_array=flow_dir_array,
                                              target_nodata=255,
                                              pixel_size=(2, -2),
                                              origin=(2, -2),
                                              projection_wkt=srs_wkt,
                                              target_path=flow_dir_path)

        # These geometries test:
        #  * Delineation works with varying geometry types
        #  * That we exclude seed pixels that are over nodata
        #  * That we exclude seed pixels off the bounds of the raster
        horizontal_line = shapely.geometry.LineString([(19, -11), (25, -11)])
        vertical_line = shapely.geometry.LineString([(21, -9), (21, -13)])
        square = shapely.geometry.box(17, -13, 21, -9)
        point = shapely.geometry.Point(21, -11)

        outflow_vector_path = os.path.join(self.workspace_dir, 'outflow.gpkg')
        pygeoprocessing.shapely_geometry_to_vector(
            [horizontal_line, vertical_line, square, point],
            outflow_vector_path,
            srs_wkt,
            'GPKG', {
                'polygon_id': ogr.OFTInteger,
                'field_string': ogr.OFTString,
                'other': ogr.OFTReal
            }, [{
                'polygon_id': 1,
                'field_string': 'hello world',
                'other': 1.111
            }, {
                'polygon_id': 2,
                'field_string': 'hello foo',
                'other': 2.222
            }, {
                'polygon_id': 3,
                'field_string': 'hello bar',
                'other': 3.333
            }, {
                'polygon_id': 4,
                'field_string': 'hello baz',
                'other': 4.444
            }],
            ogr_geom_type=ogr.wkbUnknown)

        target_watersheds_path = os.path.join(self.workspace_dir,
                                              'watersheds.gpkg')

        pygeoprocessing.routing.delineate_watersheds_d8(
            (flow_dir_path, 1),
            outflow_vector_path,
            target_watersheds_path,
            target_layer_name='watersheds_something')

        watersheds_vector = gdal.OpenEx(target_watersheds_path, gdal.OF_VECTOR)
        watersheds_layer = watersheds_vector.GetLayer('watersheds_something')
        self.assertEqual(watersheds_layer.GetFeatureCount(), 4)

        # All features should have the same watersheds, both in area and
        # geometry.
        flow_dir_bbox = pygeoprocessing.get_raster_info(
            flow_dir_path)['bounding_box']
        expected_watershed_geometry = shapely.geometry.box(*flow_dir_bbox)
        expected_watershed_geometry = expected_watershed_geometry.difference(
            shapely.geometry.box(20, -2, 22, -10))
        expected_watershed_geometry = expected_watershed_geometry.difference(
            shapely.geometry.box(20, -12, 22, -22))
        pygeoprocessing.shapely_geometry_to_vector(
            [expected_watershed_geometry],
            os.path.join(self.workspace_dir, 'foo.gpkg'),
            srs_wkt,
            'GPKG',
            ogr_geom_type=ogr.wkbGeometryCollection)

        id_to_fields = {}
        for feature in watersheds_layer:
            geometry = feature.GetGeometryRef()
            shapely_geom = shapely.wkb.loads(geometry.ExportToWkb())
            self.assertEqual(shapely_geom.area,
                             expected_watershed_geometry.area)
            self.assertEqual(
                shapely_geom.intersection(expected_watershed_geometry).area,
                expected_watershed_geometry.area)
            self.assertEqual(
                shapely_geom.difference(expected_watershed_geometry).area, 0)

            field_values = feature.items()
            id_to_fields[field_values['polygon_id']] = field_values

        outflow_vector = gdal.OpenEx(outflow_vector_path, gdal.OF_VECTOR)
        outflow_layer = outflow_vector.GetLayer()
        try:
            for feature in outflow_layer:
                self.assertEqual(id_to_fields[feature.GetField('polygon_id')],
                                 feature.items())
        finally:
            outflow_layer = None
            outflow_vector = None
Esempio n. 12
0
    def test_archive_extraction(self):
        """Datastack: test archive extraction."""
        from natcap.invest import datastack
        from natcap.invest import utils

        params = {
            'blank': '',
            'a': 1,
            'b': 'hello there',
            'c': 'plain bytestring',
            'foo': os.path.join(self.workspace, 'foo.txt'),
            'bar': os.path.join(self.workspace, 'foo.txt'),
            'data_dir': os.path.join(self.workspace, 'data_dir'),
            'raster': os.path.join(DATA_DIR, 'dem'),
            'vector': os.path.join(DATA_DIR, 'watersheds.shp'),
            'simple_table': os.path.join(DATA_DIR, 'carbon_pools_samp.csv'),
            'spatial_table': os.path.join(self.workspace, 'spatial_table.csv'),
        }
        # synthesize sample data
        os.makedirs(params['data_dir'])
        for filename in ('foo.txt', 'bar.txt', 'baz.txt'):
            data_filepath = os.path.join(params['data_dir'], filename)
            with open(data_filepath, 'w') as textfile:
                textfile.write(filename)

        with open(params['foo'], 'w') as textfile:
            textfile.write('hello world!')

        with open(params['spatial_table'], 'w') as spatial_csv:
            # copy existing DEM
            # copy existing watersheds
            # new raster
            # new vector
            spatial_csv.write('ID,path\n')
            spatial_csv.write(f"1,{params['raster']}\n")
            spatial_csv.write(f"2,{params['vector']}\n")

            # Create a raster only referenced by the CSV
            target_csv_raster_path = os.path.join(self.workspace,
                                                  'new_raster.tif')
            pygeoprocessing.new_raster_from_base(params['raster'],
                                                 target_csv_raster_path,
                                                 gdal.GDT_UInt16, [0])
            spatial_csv.write(f'3,{target_csv_raster_path}\n')

            # Create a vector only referenced by the CSV
            target_csv_vector_path = os.path.join(self.workspace,
                                                  'new_vector.geojson')
            pygeoprocessing.shapely_geometry_to_vector(
                [shapely.geometry.Point(100, 100)],
                target_csv_vector_path,
                pygeoprocessing.get_raster_info(
                    params['raster'])['projection_wkt'],
                'GeoJSON',
                ogr_geom_type=ogr.wkbPoint)
            spatial_csv.write(f'4,{target_csv_vector_path}\n')

        archive_path = os.path.join(self.workspace, 'archive.invs.tar.gz')
        datastack.build_datastack_archive(
            params, 'test_datastack_modules.archive_extraction', archive_path)
        out_directory = os.path.join(self.workspace, 'extracted_archive')
        archive_params = datastack.extract_datastack_archive(
            archive_path, out_directory)
        model_array = pygeoprocessing.raster_to_numpy_array(
            archive_params['raster'])
        reg_array = pygeoprocessing.raster_to_numpy_array(params['raster'])
        numpy.testing.assert_allclose(model_array, reg_array)
        utils._assert_vectors_equal(archive_params['vector'], params['vector'])
        pandas.testing.assert_frame_equal(
            pandas.read_csv(archive_params['simple_table']),
            pandas.read_csv(params['simple_table']))
        for key in ('blank', 'a', 'b', 'c'):
            self.assertEqual(archive_params[key], params[key],
                             f'Params differ for key {key}')

        for key in ('foo', 'bar'):
            self.assertTrue(
                filecmp.cmp(archive_params[key], params[key], shallow=False))

        spatial_csv_dict = utils.build_lookup_from_csv(
            archive_params['spatial_table'], 'ID', to_lower=True)
        spatial_csv_dir = os.path.dirname(archive_params['spatial_table'])
        numpy.testing.assert_allclose(
            pygeoprocessing.raster_to_numpy_array(
                os.path.join(spatial_csv_dir, spatial_csv_dict[3]['path'])),
            pygeoprocessing.raster_to_numpy_array(target_csv_raster_path))
        utils._assert_vectors_equal(
            os.path.join(spatial_csv_dir, spatial_csv_dict[4]['path']),
            target_csv_vector_path)
Esempio n. 13
0
    def test_calculate_land_to_grid_distance(self):
        """WindEnergy: testing 'point_to_polygon_distance' function."""
        from natcap.invest import wind_energy

        # Setup parameters for creating polygon and point shapefiles
        fields = {'vec_id': ogr.OFTInteger}
        attr_pt = [{'vec_id': 1}, {'vec_id': 2}, {'vec_id': 3}, {'vec_id': 4}]
        attr_poly = [{'vec_id': 1}, {'vec_id': 2}]

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(3157)
        projection_wkt = srs.ExportToWkt()
        origin = (443723.127327877911739, 4956546.905980412848294)
        pos_x = origin[0]
        pos_y = origin[1]

        poly_geoms = {
            'poly_1': [(pos_x + 200, pos_y), (pos_x + 250, pos_y),
                       (pos_x + 250, pos_y - 100), (pos_x + 200, pos_y - 100),
                       (pos_x + 200, pos_y)],
            'poly_2': [(pos_x, pos_y - 150), (pos_x + 100, pos_y - 150),
                       (pos_x + 100, pos_y - 200), (pos_x, pos_y - 200),
                       (pos_x, pos_y - 150)]
        }

        poly_geometries = [
            Polygon(poly_geoms['poly_1']),
            Polygon(poly_geoms['poly_2'])
        ]
        poly_vector_path = os.path.join(self.workspace_dir, 'poly_shape.shp')
        # Create polygon shapefile to use as testing input
        pygeoprocessing.shapely_geometry_to_vector(
            poly_geometries,
            poly_vector_path,
            projection_wkt,
            'ESRI Shapefile',
            fields=fields,
            attribute_list=attr_poly,
            ogr_geom_type=ogr.wkbPolygon)

        point_geometries = [
            Point(pos_x, pos_y),
            Point(pos_x + 100, pos_y),
            Point(pos_x, pos_y - 100),
            Point(pos_x + 100, pos_y - 100)
        ]
        point_vector_path = os.path.join(self.workspace_dir, 'point_shape.shp')
        # Create point shapefile to use as testing input
        pygeoprocessing.shapely_geometry_to_vector(point_geometries,
                                                   point_vector_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields,
                                                   attribute_list=attr_pt,
                                                   ogr_geom_type=ogr.wkbPoint)

        target_point_vector_path = os.path.join(self.workspace_dir,
                                                'target_point.shp')
        # Call function to test
        field_name = 'L2G'
        wind_energy._calculate_land_to_grid_distance(point_vector_path,
                                                     poly_vector_path,
                                                     field_name,
                                                     target_point_vector_path)

        exp_results = [.15, .1, .05, .05]

        point_vector = gdal.OpenEx(target_point_vector_path)
        point_layer = point_vector.GetLayer()
        field_index = point_layer.GetFeature(0).GetFieldIndex(field_name)
        for i, point_feat in enumerate(point_layer):
            result_val = point_feat.GetField(field_index)
            numpy.testing.assert_allclose(result_val, exp_results[i])
Esempio n. 14
0
    def test_ufrm_string_damage_to_infrastructure(self):
        """UFRM: handle str(int) structure indices.

        This came up on the forums, where a user had provided a string column
        type that contained integer data.  OGR returned these ints as strings,
        leading to a ``KeyError``.  See
        https://github.com/natcap/invest/issues/590.
        """
        from natcap.invest import urban_flood_risk_mitigation

        srs = osr.SpatialReference()
        srs.ImportFromEPSG(3157)
        projection_wkt = srs.ExportToWkt()
        origin = (443723.127327877911739, 4956546.905980412848294)
        pos_x = origin[0]
        pos_y = origin[1]

        aoi_geometry = [
            shapely.geometry.box(pos_x, pos_y, pos_x + 200, pos_y + 200),
        ]

        def _infra_geom(xoff, yoff):
            """Create sample infrastructure geometry at a position offset.

            The geometry will be centered on (x+xoff, y+yoff).

            Parameters:
                xoff (number): The x offset, referenced against ``pos_x`` from
                    the outer scope.
                yoff (number): The y offset, referenced against ``pos_y`` from
                    the outer scope.

            Returns:
                A ``shapely.Geometry`` of a point buffered by ``20`` centered
                on the provided (x+xoff, y+yoff) point.
            """
            return shapely.geometry.Point(pos_x + xoff,
                                          pos_y + yoff).buffer(20)

        infra_geometries = [
            _infra_geom(x_offset, 100) for x_offset in range(0, 200, 40)
        ]

        infra_fields = {'Type': ogr.OFTString}  # THIS IS THE THING TESTED
        infra_attrs = [{
            'Type': str(index)
        } for index in range(len(infra_geometries))]

        infrastructure_path = os.path.join(self.workspace_dir,
                                           'infra_vector.shp')
        pygeoprocessing.shapely_geometry_to_vector(
            infra_geometries,
            infrastructure_path,
            projection_wkt,
            'ESRI Shapefile',
            fields=infra_fields,
            attribute_list=infra_attrs,
            ogr_geom_type=ogr.wkbPolygon)

        aoi_path = os.path.join(self.workspace_dir, 'aoi.shp')
        pygeoprocessing.shapely_geometry_to_vector(
            aoi_geometry,
            aoi_path,
            projection_wkt,
            'ESRI Shapefile',
            ogr_geom_type=ogr.wkbPolygon)

        structures_damage_table_path = os.path.join(self.workspace_dir,
                                                    'damage_table_path.csv')
        with open(structures_damage_table_path, 'w') as csv_file:
            csv_file.write('"Type","damage"\n')
            for attr_dict in infra_attrs:
                type_index = int(attr_dict['Type'])
                csv_file.write(f'"{type_index}",1\n')

        aoi_damage_dict = (urban_flood_risk_mitigation.
                           _calculate_damage_to_infrastructure_in_aoi(
                               aoi_path, infrastructure_path,
                               structures_damage_table_path))

        # Total damage is the sum of the area of all infrastructure geometries
        # that intersect the AOI, with each area multiplied by the damage cost.
        # For this test, damage is always 1, so it's just the intersecting
        # area.
        self.assertEqual(len(aoi_damage_dict), 1)
        numpy.testing.assert_allclose(aoi_damage_dict[0], 5645.787282992962)
Esempio n. 15
0
    def test_clip_vector_by_vector_polygons(self):
        """WaveEnergy: testing clipping polygons from polygons."""
        from natcap.invest import wave_energy
        from natcap.invest.utils import _assert_vectors_equal

        projection_wkt = osr.SRS_WKT_WGS84_LAT_LONG
        origin = (-62.00, 44.00)
        pos_x = origin[0]
        pos_y = origin[1]

        fields_aoi = {'id': ogr.OFTInteger}
        attrs_aoi = [{'id': 1}]
        # Create polygon for the aoi
        aoi_polygon = [
            Polygon([(pos_x, pos_y),
                     (pos_x + 2, pos_y), (pos_x + 2, pos_y - 2),
                     (pos_x, pos_y - 2), (pos_x, pos_y)])
        ]

        aoi_path = os.path.join(self.workspace_dir, 'aoi.shp')
        # Create the polygon shapefile
        pygeoprocessing.shapely_geometry_to_vector(aoi_polygon,
                                                   aoi_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields_aoi,
                                                   attribute_list=attrs_aoi)

        fields_data = {'id': ogr.OFTInteger, 'myattr': ogr.OFTString}
        attrs_data = [{'id': 1, 'myattr': 'hello'}]
        # Create polygon to clip with the aoi
        data_polygon = [
            Polygon([(pos_x - 2, pos_y + 2), (pos_x + 6, pos_y - 2),
                     (pos_x + 6, pos_y - 4), (pos_x - 2, pos_y - 6),
                     (pos_x - 2, pos_y + 2)])
        ]

        data_path = os.path.join(self.workspace_dir, 'data.shp')
        # Create the polygon shapefile
        pygeoprocessing.shapely_geometry_to_vector(data_polygon,
                                                   data_path,
                                                   projection_wkt,
                                                   'ESRI Shapefile',
                                                   fields=fields_data,
                                                   attribute_list=attrs_data)

        result_path = os.path.join(self.workspace_dir, 'aoi_clipped.shp')
        wave_energy._clip_vector_by_vector(data_path, aoi_path, result_path,
                                           projection_wkt, self.workspace_dir)

        fields_expected = {'id': ogr.OFTInteger, 'myattr': ogr.OFTString}
        attrs_expected = [{'id': 1, 'myattr': 'hello'}]
        # Create polygon to clip with the aoi
        expected_polygon = aoi_polygon
        expected_path = os.path.join(self.workspace_dir, 'expected.shp')
        # Create the polygon shapefile
        pygeoprocessing.shapely_geometry_to_vector(
            expected_polygon,
            expected_path,
            projection_wkt,
            'ESRI Shapefile',
            fields=fields_expected,
            attribute_list=attrs_expected)

        _assert_vectors_equal(expected_path, result_path)