Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VolcanicAsh product to VIIRS EDR reader #3050

Merged
merged 1 commit into from
Feb 7, 2025

Conversation

pnuu
Copy link
Member

@pnuu pnuu commented Feb 6, 2025

This PR adds the VolcanicAsh product to viirs_edr reader.

The files I have (v3r0) can't be opened unless Det_QF_Size variable is dropped. I think this is becaus the same name is used as a dimension. For this, I added a possibility to drop variables defined in the reader YAML. The testing is a bit of a kludge, as the only way I could think of was to make Det_QF_Size a 2D variable instead of the scalar it is, and check that it is not in the available dataset listing.

The error coming from XArray without drop_variables is ValueError: dimension 'Det_QF_Size' already exists as a scalar variable.

  • Tests added

@pnuu pnuu added enhancement code enhancements, features, improvements component:readers labels Feb 6, 2025
@pnuu pnuu self-assigned this Feb 6, 2025
@pnuu pnuu requested review from djhoese and mraspaud as code owners February 6, 2025 13:38
Copy link

codecov bot commented Feb 6, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 96.11%. Comparing base (91e758a) to head (da46066).
Report is 14 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3050   +/-   ##
=======================================
  Coverage   96.11%   96.11%           
=======================================
  Files         383      383           
  Lines       55673    55685   +12     
=======================================
+ Hits        53511    53523   +12     
  Misses       2162     2162           
Flag Coverage Δ
behaviourtests 3.88% <0.00%> (-0.01%) ⬇️
unittests 96.21% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@coveralls
Copy link

Pull Request Test Coverage Report for Build 13180056023

Details

  • 12 of 12 (100.0%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage remained the same at 96.222%

Totals Coverage Status
Change from base Build 13139734295: 0.0%
Covered Lines: 53770
Relevant Lines: 55881

💛 - Coveralls

@djhoese
Copy link
Member

djhoese commented Feb 6, 2025

Could you provide a link to one of these files or provide the ncdump -h of one? I'm not sure I understand why it fails beyond what the error message is saying. Like yeah a dimension name and a variable name can be the same, that's what a "coordinate variable" is by CF definition. So what's wrong with this one? That it's a scalar? What is the size of the dimension?

@pnuu
Copy link
Member Author

pnuu commented Feb 6, 2025

I don't have the files at hand, so if I remember tomorrow, I'll put the file in Slack for example. And the ncdump -h output here.

Now, what I remember of the files 🤔 Both the dimension and variable are scalars. The dimension is hardcoded to integer 2, the variable is also an integer with a _FillValue attribute value -999. The dimension is used in some of the other variables, and in the ncdump -h the variable was listed after at least some of them. No idea if that really matters, just that I remember that.

@djhoese
Copy link
Member

djhoese commented Feb 6, 2025

I think it is treated like a mapping/dict so order doesn't matter, but I do know CF-standard-wise that coordinate variables aren't allowed to have fill values. But this xarray error (I assume that's what's causing the error?) seems to be happening before that. I assume the variable of that name is of (I mean "uses") the dimension with that same name?

@pnuu
Copy link
Member Author

pnuu commented Feb 6, 2025

The error rises at xr.open_dataset() call. I'll also try using netcdf4 and maybe even h5py directly tomorrow.

@pnuu
Copy link
Member Author

pnuu commented Feb 7, 2025

The dump:

$ ncdump -h JRR-VolcanicAsh_v3r0_j01_s202501290934247_e202501290935492_c202501291707471.nc
netcdf JRR-VolcanicAsh_v3r0_j01_s202501290934247_e202501290935492_c202501291707471 {
dimensions:
	Columns = 3200 ;
	Rows = 768 ;
	Det_QF_Size = 2 ;
	Det_QPI_Size = 6 ;
	Ash_QF_Size = 2 ;
	Ash_QPI_Size = 1 ;
	UnpackedDetQF_Size = 5 ;
	UnpackedRetQF_Size = 5 ;
variables:
	int StartRow ;
		StartRow:long_name = "Start row index" ;
		StartRow:units = "1" ;
	int StartColumn ;
		StartColumn:long_name = "Start column index" ;
		StartColumn:units = "1" ;
	float Latitude(Rows, Columns) ;
		Latitude:long_name = "Latitude" ;
		Latitude:_FillValue = -999.f ;
		Latitude:units = "degrees_north" ;
		Latitude:valid_range = -90.f, 90.f ;
		Latitude:comments = "Pixel latitude in field Latitude (degree)" ;
	float Longitude(Rows, Columns) ;
		Longitude:long_name = "Longitude" ;
		Longitude:_FillValue = -999.f ;
		Longitude:units = "degrees_east" ;
		Longitude:valid_range = -180.f, 180.f ;
		Longitude:comments = "Pixel longitude in field Longitude (degree)" ;
	byte AshConfidence(Rows, Columns) ;
		AshConfidence:long_name = "Ash Confidence" ;
		AshConfidence:coordinates = "Longitude Latitude" ;
		AshConfidence:_FillValue = -128b ;
		AshConfidence:units = "1" ;
	byte AshConfidenceMulti(Rows, Columns) ;
		AshConfidenceMulti:long_name = "Ash Confidence Multi" ;
		AshConfidenceMulti:coordinates = "Longitude Latitude" ;
		AshConfidenceMulti:_FillValue = -128b ;
		AshConfidenceMulti:units = "1" ;
	byte AshDetectionQPI(Rows, Columns, Det_QPI_Size) ;
		AshDetectionQPI:long_name = "Ash Confidence Product Quality Information" ;
		AshDetectionQPI:coordinates = "Longitude Latitude" ;
		AshDetectionQPI:_FillValue = -128b ;
		AshDetectionQPI:valid_range = -127b, 127b ;
		AshDetectionQPI:units = "1" ;
	byte AshDetectionQF(Rows, Columns, Det_QF_Size) ;
		AshDetectionQF:long_name = "Ash Confidence Quality Flag" ;
		AshDetectionQF:coordinates = "Longitude Latitude" ;
		AshDetectionQF:_FillValue = -128b ;
		AshDetectionQF:valid_range = -127b, 127b ;
		AshDetectionQF:units = "1" ;
	int Det_QF_Size ;
		Det_QF_Size:long_name = "Detection QF Size" ;
		Det_QF_Size:_FillValue = -999 ;
		Det_QF_Size:units = "1" ;
	float CldB1112_Tot(Rows, Columns) ;
		CldB1112_Tot:long_name = "Beta (12/11 um) for single layered clouds" ;
		CldB1112_Tot:coordinates = "Longitude Latitude" ;
		CldB1112_Tot:_FillValue = -999.f ;
		CldB1112_Tot:units = "1" ;
	float CldB1112_TotLRC(Rows, Columns) ;
		CldB1112_TotLRC:long_name = "Beta (12/11 um) for single layered clouds at LRC" ;
		CldB1112_TotLRC:coordinates = "Longitude Latitude" ;
		CldB1112_TotLRC:_FillValue = -999.f ;
		CldB1112_TotLRC:units = "1" ;
	float CldB8511_Tot(Rows, Columns) ;
		CldB8511_Tot:long_name = "Beta (8.5/11 um) for single layered clouds" ;
		CldB8511_Tot:coordinates = "Longitude Latitude" ;
		CldB8511_Tot:_FillValue = -999.f ;
		CldB8511_Tot:units = "1" ;
	float CldB8511_TotLRC(Rows, Columns) ;
		CldB8511_TotLRC:long_name = "Beta (8.5/11 um) for single layered clouds at LRC" ;
		CldB8511_TotLRC:coordinates = "Longitude Latitude" ;
		CldB8511_TotLRC:_FillValue = -999.f ;
		CldB8511_TotLRC:units = "1" ;
	float EmissCh11_Tot(Rows, Columns) ;
		EmissCh11_Tot:long_name = "8.5 um cloud emissivity array for single layered clouds" ;
		EmissCh11_Tot:coordinates = "Longitude Latitude" ;
		EmissCh11_Tot:_FillValue = -999.f ;
		EmissCh11_Tot:units = "1" ;
	float EmissCh14_Tot(Rows, Columns) ;
		EmissCh14_Tot:long_name = "11 um cloud emissivity array for single layered clouds" ;
		EmissCh14_Tot:coordinates = "Longitude Latitude" ;
		EmissCh14_Tot:_FillValue = -999.f ;
		EmissCh14_Tot:units = "1" ;
	float AshTopTemp(Rows, Columns) ;
		AshTopTemp:long_name = "Ash Top Temperature" ;
		AshTopTemp:coordinates = "Longitude Latitude" ;
		AshTopTemp:_FillValue = -999.f ;
		AshTopTemp:valid_range = 180.f, 340.f ;
		AshTopTemp:units = "K" ;
	float AshTopPress(Rows, Columns) ;
		AshTopPress:long_name = "Ash Top Pressure" ;
		AshTopPress:coordinates = "Longitude Latitude" ;
		AshTopPress:_FillValue = -999.f ;
		AshTopPress:valid_range = 0.f, 1100.f ;
		AshTopPress:units = "hPa" ;
	float AshTopHeight(Rows, Columns) ;
		AshTopHeight:long_name = "Ash Top Height" ;
		AshTopHeight:coordinates = "Longitude Latitude" ;
		AshTopHeight:_FillValue = -999.f ;
		AshTopHeight:valid_range = 0.f, 30000.f ;
		AshTopHeight:units = "m" ;
	float AshEmiss(Rows, Columns) ;
		AshEmiss:long_name = "Ash Emissivity at 11um" ;
		AshEmiss:coordinates = "Longitude Latitude" ;
		AshEmiss:_FillValue = -999.f ;
		AshEmiss:units = "1" ;
	float AshEffRad(Rows, Columns) ;
		AshEffRad:long_name = "Ash Effective Particle Size" ;
		AshEffRad:coordinates = "Longitude Latitude" ;
		AshEffRad:_FillValue = -999.f ;
		AshEffRad:valid_range = 0.f, 20.f ;
		AshEffRad:units = "1" ;
	float AshOD_VIS(Rows, Columns) ;
		AshOD_VIS:long_name = "Ash visible optical depth" ;
		AshOD_VIS:coordinates = "Longitude Latitude" ;
		AshOD_VIS:_FillValue = -999.f ;
		AshOD_VIS:valid_range = 1.f, 100.f ;
		AshOD_VIS:units = "1" ;
	float AshOD_IR(Rows, Columns) ;
		AshOD_IR:long_name = "Ash infrared optical depth" ;
		AshOD_IR:coordinates = "Longitude Latitude" ;
		AshOD_IR:_FillValue = -999.f ;
		AshOD_IR:valid_range = 1.f, 100.f ;
		AshOD_IR:units = "1" ;
	float AshMassLoading(Rows, Columns) ;
		AshMassLoading:long_name = "Ash Mass Loading" ;
		AshMassLoading:coordinates = "Longitude Latitude" ;
		AshMassLoading:_FillValue = -999.f ;
		AshMassLoading:valid_range = 0.f, 70.f ;
		AshMassLoading:units = "tons/km^2" ;
	float AshBeta(Rows, Columns) ;
		AshBeta:long_name = "Beta value for 11 and 12 microns" ;
		AshBeta:coordinates = "Longitude Latitude" ;
		AshBeta:_FillValue = -999.f ;
		AshBeta:units = "1" ;
	float AshTempErr(Rows, Columns) ;
		AshTempErr:long_name = "Estimated error in ash temperature" ;
		AshTempErr:coordinates = "Longitude Latitude" ;
		AshTempErr:_FillValue = -999.f ;
		AshTempErr:units = "K" ;
	float AshPressErr(Rows, Columns) ;
		AshPressErr:long_name = "Estimated error in ash pressure" ;
		AshPressErr:coordinates = "Longitude Latitude" ;
		AshPressErr:_FillValue = -999.f ;
		AshPressErr:units = "hPa" ;
	float AshHgtErr(Rows, Columns) ;
		AshHgtErr:long_name = "Estimated error in Ash Height" ;
		AshHgtErr:coordinates = "Longitude Latitude" ;
		AshHgtErr:_FillValue = -999.f ;
		AshHgtErr:units = "m" ;
	byte Ash_QF(Rows, Columns, Ash_QF_Size) ;
		Ash_QF:long_name = "Ash Retrieval Quality Flag" ;
		Ash_QF:coordinates = "Longitude Latitude" ;
		Ash_QF:_FillValue = -128b ;
		Ash_QF:valid_range = -127b, 127b ;
		Ash_QF:units = "1" ;
	byte Ash_PQI(Rows, Columns, Ash_QPI_Size) ;
		Ash_PQI:long_name = "Ash Retrieval Product Quality Information" ;
		Ash_PQI:coordinates = "Longitude Latitude" ;
		Ash_PQI:_FillValue = -128b ;
		Ash_PQI:valid_range = -127b, 127b ;
		Ash_PQI:units = "1" ;
	float TotMassVolAsh ;
		TotMassVolAsh:long_name = "Total Ash Loading Mass for Overall Highest Quality Pixels" ;
		TotMassVolAsh:_FillValue = -999.f ;
		TotMassVolAsh:units = "tons/km^2" ;
	float MassLoadingMax ;
		MassLoadingMax:long_name = "Maximum Ash Loading for Overall Highest Quality Pixels" ;
		MassLoadingMax:_FillValue = -999.f ;
		MassLoadingMax:units = "tons/km^2" ;
	float MassLoadingMin ;
		MassLoadingMin:long_name = "Minimum Ash Loading for Overall Highest Quality Pixels" ;
		MassLoadingMin:_FillValue = -999.f ;
		MassLoadingMin:units = "tons/km^2" ;
	float MassLoadingMean ;
		MassLoadingMean:long_name = "Mean Mass Loading for Overall Highest Quality Pixels" ;
		MassLoadingMean:_FillValue = -999.f ;
		MassLoadingMean:units = "tons/km^2" ;
	float MassLoadingStdDev ;
		MassLoadingStdDev:long_name = "Standard Deviation of Mass Loading for Overall Highest Quality Pixels" ;
		MassLoadingStdDev:_FillValue = -999.f ;
		MassLoadingStdDev:units = "tons/km^2" ;
	float AshCldHgtMax ;
		AshCldHgtMax:long_name = "Maximum Ash Cloud Height for Overall Highest Quality Pixels" ;
		AshCldHgtMax:_FillValue = -999.f ;
		AshCldHgtMax:units = "tons/km^2" ;
	float AshCldHgtMin ;
		AshCldHgtMin:long_name = "Minimum Ash Cloud Height for Overall Highest Quality Pixels" ;
		AshCldHgtMin:_FillValue = -999.f ;
		AshCldHgtMin:units = "tons/km^2" ;
	float AshCldHgtMean ;
		AshCldHgtMean:long_name = "Mean Ash Cloud Height for Overall Highest Quality Pixels" ;
		AshCldHgtMean:_FillValue = -999.f ;
		AshCldHgtMean:units = "tons/km^2" ;
	float AshCldHgtStdDev ;
		AshCldHgtStdDev:long_name = "Standard Deviation of Ash Cloud Height for Overall Highest Quality Pixels" ;
		AshCldHgtStdDev:_FillValue = -999.f ;
		AshCldHgtStdDev:units = "tons/km^2" ;
	float DetQF_OverallPerc ;
		DetQF_OverallPerc:long_name = "Percent of High Quality Overall pixels for detection" ;
		DetQF_OverallPerc:_FillValue = -999.f ;
		DetQF_OverallPerc:units = "%" ;
	float DetQF_InvDatPerc ;
		DetQF_InvDatPerc:long_name = "Percent of High Quality Invalid data pixels for detection" ;
		DetQF_InvDatPerc:_FillValue = -999.f ;
		DetQF_InvDatPerc:units = "%" ;
	float DetQF_SatZenPerc ;
		DetQF_SatZenPerc:long_name = "Percent of High Quality Satellite Zenith pixels for detection" ;
		DetQF_SatZenPerc:_FillValue = -999.f ;
		DetQF_SatZenPerc:units = "%" ;
	float DetQF_SingLyrPerc ;
		DetQF_SingLyrPerc:long_name = "Percent of High Quality Single Layer pixels for detection" ;
		DetQF_SingLyrPerc:_FillValue = -999.f ;
		DetQF_SingLyrPerc:units = "%" ;
	float DetQF_MultLyrPerc ;
		DetQF_MultLyrPerc:long_name = "Percent of High Quality Multiple Layer pixels for detection" ;
		DetQF_MultLyrPerc:_FillValue = -999.f ;
		DetQF_MultLyrPerc:units = "%" ;
	float RetQF_OverallPerc ;
		RetQF_OverallPerc:long_name = "Percent of High Quality Overall pixels for retrieval" ;
		RetQF_OverallPerc:_FillValue = -999.f ;
		RetQF_OverallPerc:units = "%" ;
	float RetQF_TcldPerc ;
		RetQF_TcldPerc:long_name = "Percent of High Quality Cloud Temperature pixels for retrieval" ;
		RetQF_TcldPerc:_FillValue = -999.f ;
		RetQF_TcldPerc:units = "%" ;
	float RetQF_EcldPerc ;
		RetQF_EcldPerc:long_name = "Percent of High Quality 11 micron emissivity at nadir pixels for retrieval" ;
		RetQF_EcldPerc:_FillValue = -999.f ;
		RetQF_EcldPerc:units = "%" ;
	float RetQF_BcldPerc ;
		RetQF_BcldPerc:long_name = "Percent of High Quality beta ratio for 11 and 12 micron pixels for retrieval" ;
		RetQF_BcldPerc:_FillValue = -999.f ;
		RetQF_BcldPerc:units = "%" ;
	int TotAttemptedRet ;
		TotAttemptedRet:long_name = "Total Attempted Retrievals" ;
		TotAttemptedRet:_FillValue = -999 ;
		TotAttemptedRet:units = "1" ;

// global attributes:
		:Conventions = "CF-1.6" ;
		:Metadata_Conventions = "CF-1.6, Unidata Dataset Discovery v1.0" ;
		:standard_name_vocabulary = "CF Standard Name Table v76" ;
		:institution = "DOC/NOAA/NESDIS/NDE > S-NPP Data Exploitation, NESDIS, NOAA, U.S. Department of Commerce" ;
		:naming_authority = "gov.noaa.nesdis.nde" ;
		:satellite_name = "NOAA-20" ;
		:instrument_name = "VIIRS" ;
		:processing_level = "NOAA Level 2" ;
		:production_site = "CSPP" ;
		:production_environment = "DB" ;
		:sensor_band_identifier = "M14,M15,M16" ;
		:sensor_band_central_radiation_wavelength = "8.55um,10.76um,12.01um" ;
		:project = "JPSS Risk Reduction: Enterprise Volcanic Ash Products" ;
		:summary = "Enterprise Volcanic Ash Detection & Height Products" ;
		:history = "Enterprise Volcanic Ash Detection Algorithm" ;
		:references = "N/A" ;
		:resolution = "750M" ;
		:time_coverage_start = "2025-01-29T09:34:24Z" ;
		:time_coverage_end = "2025-01-29T09:35:49Z" ;
		:date_created = "2025-01-29T17:07:47Z" ;
		:geospatial_lat_units = "degrees_north" ;
		:geospatial_lon_units = "degrees_east" ;
		:cdm_data_type = "swath" ;
		:title = "JRR-VolcanicAsh" ;
		:Metadata_Link = "JRR-VolcanicAsh_v3r0_j01_s202501290934247_e202501290935492_c202501291707471.nc" ;
		:history_package = "Delivery Package v3r0" ;
		:id = "8d1cb1b9-0526-4960-aedf-23047a0dda58" ;
		:geospatial_bounds = "POLYGON((73.4072571 69.3575974, 9.64101124 59.8793678, 1.07872677 63.0369987, 77.1802979 74.2180023))" ;
		:day_night_data_flag = "both" ;
		:start_orbit_number = 37300 ;
		:end_orbit_number = 37300 ;
		:ascend_descend_data_flag = 0 ;
		:geospatial_first_scanline_first_fov_lat = 69.3576f ;
		:geospatial_first_scanline_last_fov_lat = 74.218f ;
		:geospatial_last_scanline_first_fov_lat = 59.87937f ;
		:geospatial_last_scanline_last_fov_lat = 63.037f ;
		:geospatial_first_scanline_first_fov_lon = 73.40726f ;
		:geospatial_first_scanline_last_fov_lon = 77.1803f ;
		:geospatial_last_scanline_first_fov_lon = 9.641011f ;
		:geospatial_last_scanline_last_fov_lon = 1.078727f ;

@pnuu
Copy link
Member Author

pnuu commented Feb 7, 2025

Opening with XArray v2025.1.1:

In [13]: xr.open_dataset(fname)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[13], line 1
----> 1 xr.open_dataset(fname)

File ~/mambaforge/envs/py312/lib/python3.12/site-packages/xarray/backends/api.py:679, in open_dataset(filename_or_obj, engine, chunks, cache, decode_cf, mask_and_scale, decode_times, decode_timedelta, use_cftime, concat_characters, decode_coords, drop_variables, inline_array, chunked_array_type, from_array_kwargs, backend_kwargs, **kwargs)
    667 decoders = _resolve_decoders_kwargs(
    668     decode_cf,
    669     open_backend_dataset_parameters=backend.open_dataset_parameters,
   (...)
    675     decode_coords=decode_coords,
    676 )
    678 overwrite_encoded_chunks = kwargs.pop("overwrite_encoded_chunks", None)
--> 679 backend_ds = backend.open_dataset(
    680     filename_or_obj,
    681     drop_variables=drop_variables,
    682     **decoders,
    683     **kwargs,
    684 )
    685 ds = _dataset_from_backend_dataset(
    686     backend_ds,
    687     filename_or_obj,
   (...)
    697     **kwargs,
    698 )
    699 return ds

File ~/mambaforge/envs/py312/lib/python3.12/site-packages/xarray/backends/netCDF4_.py:681, in NetCDF4BackendEntrypoint.open_dataset(self, filename_or_obj, mask_and_scale, decode_times, concat_characters, decode_coords, drop_variables, use_cftime, decode_timedelta, group, mode, format, clobber, diskless, persist, auto_complex, lock, autoclose)
    679 store_entrypoint = StoreBackendEntrypoint()
    680 with close_on_error(store):
--> 681     ds = store_entrypoint.open_dataset(
    682         store,
    683         mask_and_scale=mask_and_scale,
    684         decode_times=decode_times,
    685         concat_characters=concat_characters,
    686         decode_coords=decode_coords,
    687         drop_variables=drop_variables,
    688         use_cftime=use_cftime,
    689         decode_timedelta=decode_timedelta,
    690     )
    691 return ds

File ~/mambaforge/envs/py312/lib/python3.12/site-packages/xarray/backends/store.py:59, in StoreBackendEntrypoint.open_dataset(self, filename_or_obj, mask_and_scale, decode_times, concat_characters, decode_coords, drop_variables, use_cftime, decode_timedelta)
     45 encoding = filename_or_obj.get_encoding()
     47 vars, attrs, coord_names = conventions.decode_cf_variables(
     48     vars,
     49     attrs,
   (...)
     56     decode_timedelta=decode_timedelta,
     57 )
---> 59 ds = Dataset(vars, attrs=attrs)
     60 ds = ds.set_coords(coord_names.intersection(vars))
     61 ds.set_close(filename_or_obj.close)

File ~/mambaforge/envs/py312/lib/python3.12/site-packages/xarray/core/dataset.py:747, in Dataset.__init__(self, data_vars, coords, attrs)
    744 if isinstance(coords, Dataset):
    745     coords = coords._variables
--> 747 variables, coord_names, dims, indexes, _ = merge_data_and_coords(
    748     data_vars, coords
    749 )
    751 self._attrs = dict(attrs) if attrs else None
    752 self._close = None

File ~/mambaforge/envs/py312/lib/python3.12/site-packages/xarray/core/dataset.py:460, in merge_data_and_coords(data_vars, coords)
    456     coords = create_coords_with_default_indexes(coords, data_vars)
    458 # exclude coords from alignment (all variables in a Coordinates object should
    459 # already be aligned together) and use coordinates' indexes to align data_vars
--> 460 return merge_core(
    461     [data_vars, coords],
    462     compat="broadcast_equals",
    463     join="outer",
    464     explicit_coords=tuple(coords),
    465     indexes=coords.xindexes,
    466     priority_arg=1,
    467     skip_align_args=[1],
    468 )

File ~/mambaforge/envs/py312/lib/python3.12/site-packages/xarray/core/merge.py:705, in merge_core(objects, compat, join, combine_attrs, priority_arg, explicit_coords, indexes, fill_value, skip_align_args)
    700 prioritized = _get_priority_vars_and_indexes(aligned, priority_arg, compat=compat)
    701 variables, out_indexes = merge_collected(
    702     collected, prioritized, compat=compat, combine_attrs=combine_attrs
    703 )
--> 705 dims = calculate_dimensions(variables)
    707 coord_names, noncoord_names = determine_coords(coerced)
    708 if compat == "minimal":
    709     # coordinates may be dropped in merged results

File ~/mambaforge/envs/py312/lib/python3.12/site-packages/xarray/core/variable.py:3073, in calculate_dimensions(variables)
   3071 for dim, size in zip(var.dims, var.shape, strict=True):
   3072     if dim in scalar_vars:
-> 3073         raise ValueError(
   3074             f"dimension {dim!r} already exists as a scalar variable"
   3075         )
   3076     if dim not in dims:
   3077         dims[dim] = size

ValueError: dimension 'Det_QF_Size' already exists as a scalar variable

Opening with netCDF4 works though:

In [9]: fname = "JRR-VolcanicAsh_v3r0_j01_s202501290934247_e202501290935492_c202501291707471.nc"
In [10]: with netCDF4.Dataset(fname, "r") as fid:
    ...:     print(fid["Det_QF_Size"])
    ...: 
<class 'netCDF4.Variable'>
int32 Det_QF_Size()
    long_name: Detection QF Size
    _FillValue: -999
    units: 1
unlimited dimensions: 
current shape = ()
filling on

@djhoese
Copy link
Member

djhoese commented Feb 7, 2025

Oh yeah, this file is poorly designed. We should maybe contact the creators. Especially since the global attributes suggest CF compliance. Maybe this doesn't go against CF because the variable with the same name as the dimension does not actually use that dimension, but come on. This is just confusing. Det_QF_Size, the variable, should have the same dimensionality as the dimension. Judging by the name the value of the variable is probably the same as the size of the dimension.

@djhoese
Copy link
Member

djhoese commented Feb 7, 2025

I tried running the file through a cf checker (a python package, the web ones wouldn't let me upload a file so large) and it didn't complain. I've sent a message to someone at the SSEC to see if they know who makes these files to ask for a change. The drop solution seems to be the way to go for now.

@djhoese djhoese merged commit d1352a4 into pytroll:main Feb 7, 2025
17 of 18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component:readers enhancement code enhancements, features, improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants