netcdf4-python icon indicating copy to clipboard operation
netcdf4-python copied to clipboard

NetCDF: String match to name in use

Open barronh opened this issue 5 years ago • 8 comments

  • the version of the software with which you are encountering an issue
>>> import netCDF4 as ncf
>>> print(ncf.__version__)
1.5.3
>>> print(ncf.getlibversion())
4.7.3 of Feb 19 2020 19:16:51 $
  • environmental information (i.e. Operating System, compiler info, java version, python version, etc.)
>uname -srvon
Linux atmos1 3.10.0-1062.12.1.el7.x86_64 #1 SMP Thu Dec 12 06:44:49 EST 2019 GNU/Linux
>python --version
Python 3.8.1

Installed via conda

  • a description of the issue with the steps needed to reproduce it

Code to reproduce

import netCDF4 as ncf
print(ncf.__version__)
print(ncf.getlibversion())

f = ncf.Dataset('test.nc', 'w')
f.createDimension('test', 6)
var = f.createVariable('test', 'f', ('test',))
var[:] = 0
f.setncattr('NAME', 1)

Output and Error from commands:

1.5.3
4.7.3 of Feb 19 2020 19:16:51 $
Traceback (most recent call last):
  File "test.py", line 9, in <module>
    f.setncattr('NAME', 1)
  File "netCDF4/_netCDF4.pyx", line 2844, in netCDF4._netCDF4.Dataset.setncattr
  File "netCDF4/_netCDF4.pyx", line 1617, in netCDF4._netCDF4._set_att
  File "netCDF4/_netCDF4.pyx", line 1887, in netCDF4._netCDF4._ensure_nc_success
AttributeError: NetCDF: String match to name in use

Oddly, I can add name, but not NAME in python. The error seems to point to the underlying library, but I compiled a small program against the same library without a problem. The steps to make the program, compile it, and run it are below. Along with outputs

Commands to reproduce:

cat << EOF > test.cdl
netcdf GRIDCRO2D.12US2.35L {
dimensions:
        LAT= 1 ;
variables:
        float LAT(LAT) ;
                LAT:long_name = "LAT             " ;
                LAT:units = "DEGREES         " ;
// global attributes:
                :NAME = "test" ;
data:

 LAT =
  22.84721;
}
EOF
ncgen -lc test.cdl > test.c
gcc -o test -I/work/ROMO/anaconda_envs/basic38/include -L/work/ROMO/anaconda_envs/basic38/lib -lnetcdf -lhdf5 -lhdf5_hl  -lmfhdf -ldf -ljpeg test.c
./test
ncdump test.nc

Output from commands:

netcdf test {
dimensions:
        LAT = 1 ;
variables:
        float LAT(LAT) ;
                LAT:long_name = "LAT             " ;
                LAT:units = "DEGREES         " ;

// global attributes:
                :NAME = "test" ;
data:

 LAT = 22.84721 ;
}

I'm guessing this is a "special" attribute issue, but the CAMx metadata has the property. So, I am trying to find a work around.

Thank you for any insights here.

barronh avatar Jun 17 '20 17:06 barronh

You C example will fail the same way as the python example if you specify the netCDF4 format (ncgen -lc -4 test.cdl > test.c). There must be a private attribute NAME that's used by HDF5. @WardF or @edwardhartnett, can you confirm this?

jswhit avatar Jun 17 '20 18:06 jswhit

The only workaround I can suggest now is to use the old netCDF3 format (i.e. format='NETCDF3_64BIT). That must be what CAMx uses?

jswhit avatar Jun 17 '20 18:06 jswhit

Thank you! That helps a lot. I am sorry to have confused the issue. As always, I am grateful for your help and quick response!

barronh avatar Jun 17 '20 18:06 barronh

Leaving this open for now until we decide whether it's a netcdf-c bug or not.

jswhit avatar Jun 17 '20 18:06 jswhit

I'll take a look on our end; the rest of my day is spent in meetings, but I'll see what I can figure out.

WardF avatar Jun 17 '20 19:06 WardF

@WardF - have you had a chance to check on this yet?

jswhit avatar Jun 22 '20 21:06 jswhit

having the same issue

daliagachc avatar Mar 27 '21 18:03 daliagachc

Indeed NAME is a reserved attribute name. From nc4internal.c:

/** @internal List of reserved attributes. This list must be in sorted
 * order for binary search. */
static const NC_reservedatt NC_reserved[NRESERVED] = {
    {NC_ATT_CLASS, READONLYFLAG|DIMSCALEFLAG},            /*CLASS*/
    {NC_ATT_DIMENSION_LIST, READONLYFLAG|DIMSCALEFLAG},   /*DIMENSION_LIST*/
    {NC_ATT_NAME, READONLYFLAG|DIMSCALEFLAG},             /*NAME*/
    {NC_ATT_REFERENCE_LIST, READONLYFLAG|DIMSCALEFLAG},   /*REFERENCE_LIST*/
    {NC_ATT_FORMAT, READONLYFLAG},                        /*_Format*/
    {ISNETCDF4ATT, READONLYFLAG|NAMEONLYFLAG},            /*_IsNetcdf4*/
    {NCPROPS, READONLYFLAG|NAMEONLYFLAG|MATERIALIZEDFLAG},/*_NCProperties*/
    {NC_ATT_COORDINATES, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4Coordinates*/
    {NC_ATT_DIMID_NAME, READONLYFLAG|DIMSCALEFLAG|MATERIALIZEDFLAG},/*_Netcdf4Dimid*/
    {SUPERBLOCKATT, READONLYFLAG|NAMEONLYFLAG},/*_SuperblockVersion*/
    {NC_ATT_NC3_STRICT_NAME, READONLYFLAG|MATERIALIZEDFLAG}, /*_nc3_strict*/
};

Unfortunately this is not under our control, the first 4 reserved names are part of the HDF5 dimension scale API, which is used for dimensions in netCDF/HDF5 files.

The only way to really fix this is to catch the definition of a "NAME" attribute, and then really name it _netcdf_NAME in the file, and then, when reading the file, intercept "_netcdf_NAME" and present it to the user as attribute "NAME".

captainkirk99 avatar Mar 28 '21 15:03 captainkirk99