Repository: rasterio/rasterio

Issue:
Georeference metadata not read from some GRIB files
## Expected behavior and actual behavior.

I have been working with GRIB (version 2) data and have run into an issue where the georeference metadata are not extracted (i.e., the CRS is missing, affine parameters are incorrect, etc.). However, if I simply use the standard GDAL Python bindings, the metadata are extracted. The data I am working with is from the [NCEP SREF](http://www.nco.ncep.noaa.gov/pmb/products/sref/) weather forecast model.

## Steps to reproduce the problem.
I use `rasterio` as follows:
```python
import rasterio
dat = rasterio.open('my_grib_file.grib2')
dat.profile
```
which produces the following output
```python
>>> {'affine': Affine(1.0, 0.0, -0.5, 0.0, 1.0, -0.5),
 'count': 523,
 'crs': CRS({}),
 'driver': 'GRIB',
 'dtype': 'float64',
 'height': 129,
 'nodata': None,
 'tiled': False,
 'transform': (-0.5, 1.0, 0.0, -0.5, 0.0, 1.0),
 'width': 185}
```
With `osgeo.gdal` (in a separate session)
```python
from osgeo import gdal
dat = gdal.Open('my_grib_file.grib2')
dat.GetProjectionRef()
dat.GetGeoTransform()
```
which produces
```python
>>> 'PROJCS["unnamed",GEOGCS["Coordinate System imported from GRIB file",DATUM["unknown",SPHEROID["Sphere",6371229,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic_2SP"],PARAMETER["standard_parallel_1",25],PARAMETER["standard_parallel_2",25],PARAMETER["latitude_of_origin",25],PARAMETER["central_meridian",265],PARAMETER["false_easting",0],PARAMETER["false_northing",0]]'
>>> (-4246424.496915466, 40635.0, 0.0, 4388899.238982436, 0.0, -40635.0)
```

## Operating systems

RHEL 6

## Rasterio version and provenance

rasterio 0.36.0 via conda-forge
gdal 2.1.3 via conda-forge
python 3.6.4 via conda-forge

## Other information

I have verified that both `osgeo.gdal` and `rasterio` are using the same GDAL C library. When I use the same methods as above on another GRIB (this time version 1) from a different weather forecast model, the georeference metadata are read correctly. This would indicate it could be an issue with individual files, but, as I show above, the same GDAL library reads the correct georeference data when not using `rasterio`.

I determined that the issue occurs when `GDALGetProjectionRef` is called in `read_crs` from `_base.pyx`. What I did then was to create a small C program that uses `GDALGetProjectionRef` to access the georeference information and print it to STDOUT. That worked just fine and produced the same information as when using `osgeo.gdal`. I also built rasterio from source in a separate conda environment and still had the same problem. This is what ultimately led me to believe that the issue has something to do with what is getting passed around in `rasterio` versus the GDAL C library itself or something with my conda environments.


Discussion:
I think it may be that rasterio 0.36 is in error. There are more recent 1.0 pre-releases in conda-forge. Could you try the latest one?

Also, can you link a specific GRIB file here that will help me reproduce the problem? I'm not sure how to navigate the NCEP FTP site.
@nawendt To install the pre-release version, use `conda install -c conda-forge/label/dev rasterio`.
@sgillies Here is a [link](http://www.ftp.ncep.noaa.gov/data/nccf/com/sref/prod/sref.20180117/21/pgrb/sref_arw.t21z.pgrb132.ctl.f00.grib2) to a SREF grib file. They are only kept on the server 6 days or so. I had no better luck using rasterio 1.0a12.
This is a very strange issue indeed. I confirmed the same behavior with the file `sref_arw.t15z.pgrb132.ctl.f00.grib2` when opening with rasterio (1.0.2) & with the GDAL python bindings.

However, when I do `rio info sref_arw.t15z.pgrb132.ctl.f00.grib2`, I get:
```
...
"transform": [16232.0, 0.0, -5640783.863757296, 0.0, -16232.0, 4355613.353550392, 0.0, 0.0, 1.0]
...
"crs": "+a=6371229 +b=6371229 +lat_0=50 +lat_1=50 +lat_2=50 +lon_0=253 +no_defs +proj=lcc +units=m +x_0=0 +y_0=0"
...
```
Which matches `gdalinfo`:
```
PROJCS["unnamed",
    GEOGCS["Coordinate System imported from GRIB file",
        DATUM["unknown",
            SPHEROID["Sphere",6371229,0]],
        PRIMEM["Greenwich",0],
        UNIT["degree",0.0174532925199433]],
    PROJECTION["Lambert_Conformal_Conic_2SP"],
    PARAMETER["standard_parallel_1",50],
    PARAMETER["standard_parallel_2",50],
    PARAMETER["latitude_of_origin",50],
    PARAMETER["central_meridian",253],
    PARAMETER["false_easting",0],
    PARAMETER["false_northing",0]]
Origin = (-5640783.863757296465337,4355613.353550392203033)
Pixel Size = (16232.000000000000000,-16232.000000000000000)
```

Looks like it is needing the environment for some reason. It works like this:
```python
with rasterio.Env(), rasterio.open('sref_arw.t15z.pgrb132.ctl.f00.grib2') as dat:
    print(dat.profile)
```
Output:
```
{'driver': 'GRIB', 'dtype': 'float64', 'nodata': None, 'width': 697, 'height': 553, 'count': 551, 'crs': CRS({'proj': 'lcc', 'lat_1': 50, 'lat_2': 50, 'lat_0': 50, 'lon_0': 253, 'x_0': 0, 'y_0': 0, 'a': 6371229, 'b': 6371229, 'units': 'm', 'no_defs': True}), 'transform': Affine(16232.0, 0.0, -5640783.863757296,
       0.0, -16232.0, 4355613.353550392), 'tiled': False}
```
Confirmed.

```
>>> with rasterio.open('/Users/sean/Downloads/nam.t00z.awip3d00.tm02.grib2') as src:
...     print(src.crs)
...
None
>>> with rasterio.Env(), rasterio.open('/Users/sean/Downloads/nam.t00z.awip3d00.tm02.grib2') as src:
...     print(src.crs)
...
+a=6371229 +b=6371229 +lat_0=25 +lat_1=25 +lat_2=25 +lon_0=265 +no_defs +proj=lcc +units=m +x_0=0 +y_0=0
```

Interesting! 🤔 
It is still persists.
This is a matter of GDAL being able to find PROJ data. Setting PROJ_LIB in our environments is the only means we have of configuring GDAL 2.x.

With PROJ_LIB set, this is what I get when I open one of GDAL's test files.

```
>>> import rasterio
>>> with rasterio.open("/home/sean/projects/gdal/autotest/gdrivers/data/grib/one_one.grib2") as dataset:
...     print(dataset.crs)
...
GEOGCS["Coordinate System imported from GRIB file",DATUM["unnamed",SPHEROID["Sphere",6371229,0]],PRIMEM["Greenwich",0],UNIT["degree",
0.0174532925199433,AUTHORITY["EPSG","9122"]],AXIS["Latitude",NORTH],AXIS["Longitude",EAST]]
```

With an installed rasterio 1.0.28 wheel and no PROJ_LIB set I get

```
>>> import rasterio
>>> with rasterio.open("/home/sean/projects/gdal/autotest/gdrivers/data/grib/one_one.grib2") as dataset:
...     print(dataset.crs)
...
GEOGCS["Coordinate System imported from GRIB file",DATUM["unknown",SPHEROID["Sphere",6371229,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433]]
```

It's not empty like you report, but is missing data. 

Calling rasterio.open() does import rasterio.env and that is supposed to patch our environments appropriately in the wheel case, setting PROJ_LIB. It looks like that is not working. I'll investigate.
Just ran into this again recently: https://gis.stackexchange.com/a/357686/144357
@snowman2 it's not a rasterio regression. If PROJ_LIB is set, there won't be a problem.
I just tested that as I was pretty sure `PROJ_LIB` was set:
![image](https://user-images.githubusercontent.com/8699967/78910067-fdf34000-7a49-11ea-806d-202fe6260a67.png)

![image](https://user-images.githubusercontent.com/8699967/78910181-27ac6700-7a4a-11ea-9bd2-6f289d03c1cb.png)

Just did some debugging and it seems to have something to do with defaults used in `Env.from_defaults()`:

```python
>>> import rasterio
>>> with rasterio.Env.from_defaults(), rasterio.open("CMC_caps_HGT_ISBL_0050_ps3km_2018090900_P005.grib2") as rds:
...     print(rds.crs)
... 
None
```


```python
>>> import rasterio
>>> with rasterio.Env(), rasterio.open("CMC_caps_HGT_ISBL_0050_ps3km_2018090900_P005.grib2") as rds:
...     print(rds.crs)
... 
CRS.from_wkt('PROJCS["unnamed",GEOGCS["Coordinate System imported from GRIB file",DATUM["unnamed",SPHEROID["Sphere",6371229,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Polar_Stereographic"],PARAMETER["latitude_of_origin",60],PARAMETER["central_meridian",264],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["Metre",1],AXIS["Easting",SOUTH],AXIS["Northing",SOUTH]]')

```

I modified this part:
https://github.com/mapbox/rasterio/blob/5af075c1c0f260100e831b281909e8e5dee7f571/rasterio/env.py#L226-L228
To return just the `Env` object without the default options and it works:
```python
>>> import rasterio
>>> rds = rasterio.open("CMC_caps_HGT_ISBL_0050_ps3km_2018090900_P005.grib2")
>>> rds.crs
CRS.from_wkt('PROJCS["unnamed",GEOGCS["Coordinate System imported from GRIB file",DATUM["unnamed",SPHEROID["Sphere",6371229,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Polar_Stereographic"],PARAMETER["latitude_of_origin",60],PARAMETER["central_meridian",264],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["Metre",1],AXIS["Easting",SOUTH],AXIS["Northing",SOUTH]]')
```
I think it has to do with this option:
https://github.com/mapbox/rasterio/blob/5af075c1c0f260100e831b281909e8e5dee7f571/rasterio/env.py#L101

![image](https://user-images.githubusercontent.com/8699967/83468856-a10d7800-a443-11ea-96c8-de1c7b4cbaf9.png)

```python
>>> import rasterio
>>> rds = rasterio.open("CMC_caps_HGT_ISBL_0050_ps3km_2018090900_P005.grib2")
>>> rds.crs
CRS.from_wkt('PROJCS["unnamed",GEOGCS["Coordinate System imported from GRIB file",DATUM["unnamed",SPHEROID["Sphere",6371229,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Polar_Stereographic"],PARAMETER["latitude_of_origin",60],PARAMETER["central_meridian",264],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["Metre",1],AXIS["Easting",SOUTH],AXIS["Northing",SOUTH]]')
```
More debugging:
```python
>>> import rasterio
>>> with rasterio.Env(CHECK_WITH_INVERT_PROJ=False), rasterio.open("CMC_caps_HGT_ISBL_0050_ps3km_2018090900_P005.grib2") as rds:
...     print(rds.crs)
... 
PROJCS["unnamed",GEOGCS["Coordinate System imported from GRIB file",DATUM["unnamed",SPHEROID["Sphere",6371229,0]],PRIMEM["Greenwich",0],UNIT["degree",0.0174532925199433,AUTHORITY["EPSG","9122"]]],PROJECTION["Polar_Stereographic"],PARAMETER["latitude_of_origin",60],PARAMETER["central_meridian",264],PARAMETER["false_easting",0],PARAMETER["false_northing",0],UNIT["Metre",1],AXIS["Easting",SOUTH],AXIS["Northing",SOUTH]]
>>> with rasterio.Env(CHECK_WITH_INVERT_PROJ=True), rasterio.open("CMC_caps_HGT_ISBL_0050_ps3km_2018090900_P005.grib2") as rds:
...     print(rds.crs)
... 
None
```
Using GDAL Python, we get a useful error message:
```python
>>> from osgeo import gdal
>>> gdal.SetConfigOption("CHECK_WITH_INVERT_PROJ", "YES")
>>> dat = gdal.Open("CMC_caps_HGT_ISBL_0050_ps3km_2018090900_P005.grib2")
Warning 1: Unable to perform coordinate transformations, so the correct projected geotransform could not be deduced from the lat/long control points.  Defaulting to ungeoreferenced.
>>> dat.GetProjectionRef()
''
```
Interesting :thinking:  By the way, you see an error message with the Python bindings because it prints to stderr by default regardless of error level. Rasterio sends this to the logger, which has to be configured.
@snowman2 without setting `CHECK_WITH_INVERT_PROJ` in that script, do you get the results you expect?

And what is up with this GRIB file that PROJ functions are called when it is opened? Generally, `Open` does very little work at all, but the GRIB driver must be an exception.
> without setting CHECK_WITH_INVERT_PROJ in that script, do you get the results you expect?

I just checked that the CRS and geotransform were provided.

> And what is up with this GRIB file that PROJ functions are called when it is opened?

:man_shrugging:. I guess GRIB stores things in a different way.

Resolving patch:
diff --git a/rasterio/env.py b/rasterio/env.py
--- a/rasterio/env.py
+++ b/rasterio/env.py
@@ -98,7 +98,6 @@ def default_options(cls):
         dict
         """
         return {
-            'CHECK_WITH_INVERT_PROJ': True,
             'GTIFF_IMPLICIT_JPEG_OVR': False,
             "RASTERIO_ENV": True
         }
diff --git a/rasterio/warp.py b/rasterio/warp.py
--- a/rasterio/warp.py
+++ b/rasterio/warp.py
@@ -453,7 +453,7 @@ def calculate_default_transform(
     if any(x is None for x in (left, bottom, right, top)) and not gcps:
         raise ValueError("Either four bounding values or ground control points"
                          "must be specified")
-    
+
     if (dst_width is None) != (dst_height is None):
         raise ValueError("Either dst_width and dst_height must be specified "
                          "or none of them.")
@@ -467,7 +467,8 @@ def calculate_default_transform(
         raise ValueError("Resolution cannot be used with dst_width and dst_height.")
 
     dst_affine, dst_width, dst_height = _calculate_default_transform(
-        src_crs, dst_crs, width, height, left, bottom, right, top, gcps)
+        src_crs, dst_crs, width, height, left, bottom, right, top, gcps
+    )
 
     # If resolution is specified, Keep upper-left anchored
     # adjust the transform resolutions


Test patch:
diff --git a/tests/test_env.py b/tests/test_env.py
--- a/tests/test_env.py
+++ b/tests/test_env.py
@@ -204,7 +204,6 @@ def test_env_defaults(gdalenv):
     assert env.options['foo'] == 'x'
     assert not env.context_options
     with env:
-        assert get_gdal_config('CHECK_WITH_INVERT_PROJ') is True
         assert get_gdal_config('GTIFF_IMPLICIT_JPEG_OVR') is False
         assert get_gdal_config("RASTERIO_ENV") is True
 
diff --git a/tests/test_warp.py b/tests/test_warp.py
--- a/tests/test_warp.py
+++ b/tests/test_warp.py
@@ -1,12 +1,12 @@
-import json
 """rasterio.warp module tests"""
 
+import json
 import sys
 
-import pytest
 from affine import Affine
 import numpy as np
 from numpy.testing import assert_almost_equal
+import pytest
 
 import rasterio
 from rasterio.control import GroundControlPoint
@@ -1199,7 +1199,7 @@ def test_resample_default_invert_proj(method):
 
     with rasterio.open("tests/data/world.rgb.tif") as src:
         source = src.read(1)
-        profile = src.profile.copy()
+        profile = src.profile
 
     dst_crs = "EPSG:32619"
 
@@ -1213,16 +1213,23 @@ def test_resample_default_invert_proj(method):
 
     out = np.empty(shape=(dst_height, dst_width), dtype=np.uint8)
 
-    out = np.empty(src.shape, dtype=np.uint8)
-    reproject(
-        source,
-        out,
-        src_transform=src.transform,
-        src_crs=src.crs,
-        dst_transform=dst_affine,
-        dst_crs=dst_crs,
-        resampling=method,
-    )
+    # GDAL 1.11 needs to have this config option set on to match the
+    # default results in later versions.
+    if gdal_version.major == 1:
+        options = dict(CHECK_WITH_INVERT_PROJ=True)
+    else:
+        options = {}
+
+    with rasterio.Env(**options):
+        reproject(
+            source,
+            out,
+            src_transform=src.transform,
+            src_crs=src.crs,
+            dst_transform=dst_affine,
+            dst_crs=dst_crs,
+            resampling=method,
+        )
 
     assert out.mean() > 0