Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Checks ISMIP7 NetCDF simulation datasets for compliance with the [ISMIP7 data re
4. **Time** — time dimension is present, unlimited, and monotonically increasing; annual cadence; experiment start/end dates and duration match `experiments_ismip7.csv`, accounting for the variable type (ST or FL, see [Time encoding](#time-encoding)).
5. **Attributes** — required global and coordinate attributes are present and have correct values; `standard_name` matches data request; `_FillValue` equals the NetCDF4 default for the variable's dtype; variable and time are float32; `scale_factor` and `add_offset` are not allowed.

Compliance criteria are defined in `conventions/ISMIP7_variable_request.xlsx` (variable metadata) and `experiments_ismip7.csv` (valid experiment year ranges and durations).
Compliance criteria are defined in `conventions/ISMIP7_variable_request.csv` (variable metadata) and `experiments_ismip7.csv` (valid experiment year ranges and durations).

---

Expand Down Expand Up @@ -38,7 +38,7 @@ conda env create -f isschecker_env.yml
conda activate isschecker
```

Dependencies: Python 3.14, `numpy` 2.4, `pandas` 3.0, `openpyxl` 3.1, `xarray` 2026.4, `cftime` 1.6, `netCDF4` 1.7, `tqdm` 4.67.
Dependencies: Python 3.14, `numpy` 2.4, `pandas` 3.0, `xarray` 2026.4, `cftime` 1.6, `netCDF4` 1.7, `tqdm` 4.67.

---

Expand Down
10 changes: 5 additions & 5 deletions compliance_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
DEFAULT_VARIABLE_LIST = "ismip7_scalars"
VARIABLE_LIST_CHOICES = ("ismip7_scalars", "ismip7_xyt", "ismip7")

VARIABLE_REQUEST_XLSX = os.path.join("conventions", "ISMIP7_variable_request.xlsx")
VARIABLE_REQUEST_CSV = os.path.join("conventions", "ISMIP7_variable_request.csv")

EXPERIMENTS_ISMIP7_CSV_FILENAME = "experiments_ismip7.csv"

Expand Down Expand Up @@ -162,7 +162,7 @@ def run_checker(
ismip_var=ismip_var,
mandatory_variables=mandatory_variables,
experiments=experiments_ismip7,
criteria_file=VARIABLE_REQUEST_XLSX,
criteria_file=VARIABLE_REQUEST_CSV,
)

log_path = os.path.join(source_path, "compliance_checker_log.txt")
Expand Down Expand Up @@ -206,13 +206,13 @@ def _parse_args() -> argparse.Namespace:


def _load_criteria(workdir: str, variable_list: str):
excel_path = os.path.join(workdir, VARIABLE_REQUEST_XLSX)
csv_path = os.path.join(workdir, VARIABLE_REQUEST_CSV)
try:
df = pd.read_excel(excel_path, sheet_name="ISM")
df = pd.read_csv(csv_path)
except IOError:
print(
"ERROR: Unable to open the variable request file. Is the path correct? "
+ excel_path
+ csv_path
)
raise

Expand Down
40 changes: 40 additions & 0 deletions conventions/ISMIP7_variable_request.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
long_name,Dim,Type,Variable Name,standard_name,units,Mandatory (yes/no),Comment,min_value_ais,max_value_ais,min_value_gris,max_value_gris
Ice thickness,"x,y,t",ST,lithk,land_ice_thickness,m,yes,Ice thickness of the ice sheet,0,5000,0,5000
Surface elevation,"x,y,t",ST,orog,surface_altitude,m,yes,Surface elevation of the ice sheet,0,4500,0,4500
Bedrock elevation,"x,y,t",ST,topg,bedrock_altitude,m,yes,The bedrock topography (may change during the projections),-7000,4000,-4000,4000
Ice base elevation,"x,y,t",ST,base,,m,yes,Should get standard name land_ice_temperature,-4000,4000,-4000,4000
Geothermal heat flux,"x,y,t",FL,hfgeoubed,upward_geothermal_heat_flux_in_land_ice,W m-2,no,Geothermal Heat flux at the ice interface,0,0.3,0,0.3
Surface mass balance flux,"x,y,t",FL,acabf,land_ice_surface_specific_mass_balance_flux,kg m-2 s-1,yes,Surface Mass Balance flux,-0.0006,0.001,-0.0006,0.001
Basal mass balance flux beneath grounded ice,"x,y,t",FL,libmassbfgr,land_ice_basal_specific_mass_balance_flux,kg m-2 s-1,yes,Basal mass balance flux (only beneath grounded ice),-0.0003,0.0001,-0.0003,0.0001
Basal mass balance flux beneath floating ice,"x,y,t",FL,libmassbffl,land_ice_basal_specific_mass_balance_flux,kg m-2 s-1,yes,Basal mass balance flux (only beneath floating ice),-0.008,0.001,-0.008,0.001
Ice thickness imbalance,"x,y,t",FL,dlithkdt,tendency_of_land_ice_thickness,m s-1,yes,dHdt,-0.0001,0.0001,-0.0001,0.0001
Surface velocity in x,"x,y,t",ST,xvelsurf,land_ice_surface_x_velocity,m s-1,no,u-velocity at land ice surface,-0.0004,0.0004,-0.0008,0.0008
Surface velocity in y,"x,y,t",ST,yvelsurf,land_ice_surface_y_velocity,m s-1,no,v-velocity at land ice surface,-0.0004,0.0004,-0.0008,0.0008
Surface velocity in z,"x,y,t",ST,zvelsurf,land_ice_surface_upward_velocity,m s-1,no,w-velocity at land ice surface,-4.00E-06,4e-06,-8.00E-06,8e-06
Basal velocity in x,"x,y,t",ST,xvelbase,land_ice_basal_x_velocity,m s-1,no,u-velocity at land ice base,-0.0004,0.0004,-0.0008,0.0008
Basal velocity in y,"x,y,t",ST,yvelbase,land_ice_basal_y_velocity,m s-1,no,v-velocity at land ice base,-0.0004,0.0004,-0.0008,0.0008
Basal velocity in z,"x,y,t",ST,zvelbase,land_ice_basal_upward_velocity,m s-1,no,w-velocity at land ice base,-5.00E-06,5e-06,-8.00E-06,8e-06
Mean velocity in x,"x,y,t",ST,xvelmean,land_ice_vertical_mean_x_velocity,m s-1,yes,Vertical mean land ice velocity ,-0.0004,0.0004,-0.0008,0.0008
Mean velocity in y,"x,y,t",ST,yvelmean,land_ice_vertical_mean_y_velocity,m s-1,yes,The vertical mean land ice velocity is the average from the bedrock to the surface of the ice,-0.0004,0.0004,-0.0008,0.0008
Surface temperature,"x,y,t",ST,litemptop,temperature_at_top_of_ice_sheet_model,K,no,Ice temperature at surface,183,290,183,290
Depth average temperature,"x,y,t",ST,litempavg,,K,no,Should get standard name land_ice_temperature,183,290,183,290
Vertical Basal temperature gradient beneath grounded ice sheet,"x,y,t",ST,litempgradgr,,K m-1,no,"Vertical Basal temperature gradient beneath grounded ice sheet, should get a standard name",-10,10,-10,10
Vertical Basal temperature gradient beneath floating ice shelf,"x,y,t",ST,litempgradfl,,K m-1,no,"Vertical Basal temperature gradient beneath floating ice shelf, should get a standard name",-10,10,-10,10
Basal temperature beneath grounded ice sheet,"x,y,t",ST,litempbotgr,temperature_at_base_of_ice_sheet_model,K,no,Ice temperature at base of grounded ice sheet,183,290,183,290
Basal temperature beneath floating ice shelf,"x,y,t",ST,litempbotfl,temperature_at_base_of_ice_sheet_model,K,no,Ice temperature at base of floating ice shelf,183,290,183,290
Basal drag,"x,y,t",ST,strbasemag,land_ice_basal_drag,Pa,yes,Basal drag,0,300000,0,300000
Calving flux,"x,y,t",FL,licalvf,land_ice_specific_mass_flux_due_to_calving,kg m-2 s-1,yes,Ice mass change resulting from iceberg calving. Only for grid cells in contact with ocean,-1E+11,0,-1E+11,0
Ice front melt flux,"x,y,t",FL,lifmassbf,,kg m-2 s-1,yes,Ice mass change resulting from ice front melting. Only for grid cells in contact with ocean. Should get standard name: land_ice_specific_mass_flux_due_to_ice_front_melting,-1E+11,0,-1E+11,0
Land ice area fraction,"x,y,t",ST,sftgif,land_ice_area_fraction,1,yes,"Fraction of grid cell covered by land ice (ice sheet, ice shelf, ice cap, glacier)",0,1,0,1
Grounded ice sheet area fraction,"x,y,t",ST,sftgrf,grounded_ice_sheet_area_fraction,1,yes,"Fraction of grid cell covered by grounded ice sheet, where grounded indicates that the quantity correspond to the ice sheet that flows over bedrock",0,1,0,1
Floating ice sheet area fraction,"x,y,t",ST,sftflf,floating_ice_shelf_area_fraction,1,yes,Fraction of grid cell covered by ice sheet flowing over seawater,0,1,0,1
Total ice mass,t,ST,lim,land_ice_mass,kg,yes,"spatial integration, volume times density",0,1e+25,0,1e+25
Mass above floatation,t,ST,limnsw,land_ice_mass_not_displacing_sea_water,kg,yes,"spatial integration, volume times density",0,1e+25,0,1e+25
Grounded ice area,t,ST,iareagr,grounded_ice_sheet_area,m^2,yes,spatial integration,0,1e+25,0,1e+25
Floating ice area,t,ST,iareafl,floating_ice_shelf_area,m^2,yes,spatial integration,0,1e+25,0,1e+25
Total SMB flux,t,FL,tendacabf,tendency_of_land_ice_mass_due_to_surface_mass_balance,kg s-1,yes,spatial integration,0,1e+25,0,1e+25
Total BMB flux beneath grounded ice,t,FL,tendlibmassbfgr,tendency_of_land_ice_mass_due_to_basal_mass_balance,kg s-1,yes,spatial integration,0,1e+25,0,1e+25
Total BMB flux beneath floating ice,t,FL,tendlibmassbffl,tendency_of_land_ice_mass_due_to_basal_mass_balance,kg s-1,yes,spatial integration (computed beneath floating ice only),0,1e+25,0,1e+25
Total calving flux,t,FL,tendlicalvf,tendency_of_land_ice_mass_due_to_calving,kg s-1,yes,spatial integration,0,1e+25,0,1e+25
Total ice front melting flux,t,FL,tendlifmassbf,,kg s-1,yes,"spatial integration, should get standard name: tendency_of_land_ice_mass_due_to_ice_front_melting",0,1e+25,0,1e+25
Total grounding line flux,t,FL,tendligroundf,,kg s-1,yes,"spatial integration, should get a standard name",0,1e+25,0,1e+25
Binary file removed conventions/ISMIP7_variable_request.xlsx
Binary file not shown.
2 changes: 1 addition & 1 deletion generate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,6 @@ python generate/generate_test_files.py --grid GrIS_16000m --scenario ctrl \

## Notes

- Variable metadata is read from `conventions/ISMIP7_variable_request.xlsx`; grid definitions from the top-level `gdfs/` directory.
- Variable metadata is read from `conventions/ISMIP7_variable_request.csv`; grid definitions from the top-level `gdfs/` directory.
- `group`, `model`, `contact_name`, and `contact_email` are hardcoded in `create_netcdf_file()` to synthetic defaults — edit there to customise.
- Generated files are synthetic and intended for testing the compliance checker, not for scientific use.
28 changes: 14 additions & 14 deletions generate/generate_test_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,14 @@ def parse_grid_file(gdf_file):
return grid_params


def read_variable_criteria(excel_file, include_non_mandatory=False):
def read_variable_criteria(csv_file, include_non_mandatory=False):
"""
Read variable criteria from Excel file.
Read variable criteria from CSV file.

Parameters
----------
excel_file : str
Path to the Excel file
csv_file : str
Path to the CSV file
include_non_mandatory : bool
Whether to include non-mandatory variables

Expand All @@ -104,8 +104,8 @@ def read_variable_criteria(excel_file, include_non_mandatory=False):

variables = {}

# Read the Excel file
df = pd.read_excel(excel_file, sheet_name='ISM')
# Read the CSV file
df = pd.read_csv(csv_file)

# Filter out rows that don't have variable names
df = df.dropna(subset=['Variable Name'])
Expand All @@ -128,13 +128,13 @@ def read_variable_criteria(excel_file, include_non_mandatory=False):
variables[var_name] = {
'dimensions': dimensions,
'type': row['Type'],
'description': row['long_name'], # Use long_name from Excel
'description': row['long_name'], # Use long_name from CSV
'standard_name': row['standard_name'] if pd.notna(row['standard_name']) else '',
'units': str(row['units']) if pd.notna(row['units']) else '',
'mandatory': row['Mandatory (yes/no)'].lower() == 'yes',
}

# Collect any min_/max_ columns (case-insensitive) from the Excel sheet
# Collect any min_/max_ columns (case-insensitive) from the CSV
# Normalize keys to lowercase (e.g., 'min_gris', 'max_ais') and store
for col in df.columns:
try:
Expand Down Expand Up @@ -261,13 +261,13 @@ def create_netcdf_file(output_file, grid_name='GrIS_16000m', scenario='ctrl', st
xinc = grid_params['xinc']
yinc = grid_params['yinc']

# Read variable criteria from Excel file
excel_file = conventions_dir / 'ISMIP7_variable_request.xlsx'
if not excel_file.exists():
print(f"Warning: {excel_file} not found")
# Read variable criteria from CSV file
csv_file = conventions_dir / 'ISMIP7_variable_request.csv'
if not csv_file.exists():
print(f"Warning: {csv_file} not found")
variables = {}
else:
variables = read_variable_criteria(str(excel_file), include_non_mandatory)
variables = read_variable_criteria(str(csv_file), include_non_mandatory)

# Create coordinate arrays
x = np.arange(nx, dtype=np.float32) * xinc + xfirst
Expand Down Expand Up @@ -688,7 +688,7 @@ def create_multiple_files(output_dir=None, n_files=3, conventions_dir=None,
parser.add_argument(
'--include-non-mandatory',
action='store_true',
help='Include non-mandatory variables from the ISM Excel variable list'
help='Include non-mandatory variables from the ISM CSV variable list'
)
parser.add_argument(
'--multiple',
Expand Down
1 change: 0 additions & 1 deletion isschecker_env.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ dependencies:
# Core scientific python
- numpy=2.4.3
- pandas=3.0.2
- openpyxl=3.1.5
- pytest=8.4.2
- tqdm=4.67.3

Expand Down
Loading