@@ -1120,7 +1120,7 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
11201120 temperature = None ,
11211121 wind_u = 0 ,
11221122 wind_v = 0 ,
1123- pressure_conversion_factor = "Pa" ,
1123+ pressure_conversion_factor = None ,
11241124 ):
11251125 """Define the atmospheric model for this Environment.
11261126
@@ -1219,10 +1219,14 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
12191219 return a corresponding wind-v in m/s.
12201220 pressure_conversion_factor : string, int, float
12211221 This defines the pressure conversion factor to Pa when type is
1222- ``forecast`` or ``reanalysis``. The pressure unit from the data may
1223- not be in Pascal, so the correction is necessary. Valid strings are
1224- ("mbar", "hPa", "Pa"), or a strictly positive number if using a
1225- custom pressure unit.
1222+ ``forecast``, ``reanalysis``, or ``ensemble``. The pressure unit
1223+ from the data may not be in Pascal, so the correction is necessary.
1224+ Valid strings are ``"mbar"``, ``"hPa"``, or ``"Pa"``, or a strictly
1225+ positive number if using a custom pressure unit. ERA5 and ECMWF
1226+ reanalysis ``.nc`` files store pressure in hPa; use ``"hPa"`` for
1227+ those. MERRA2 files and online forecast models (GFS, NAM, RAP,
1228+ HRRR) store pressure in Pa; the default ``"Pa"`` is correct for
1229+ these.
12261230
12271231 Returns
12281232 -------
@@ -1272,27 +1276,36 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
12721276 case "windy" :
12731277 self .process_windy_atmosphere (file )
12741278 case "forecast" | "reanalysis" | "ensemble" :
1275- conversion_factor = 1
1276- if not isinstance (pressure_conversion_factor , (float , int , str )):
1277- raise ValueError (
1278- "Argument 'pressure_conversion_factor' must be numeric or a standard pressure unit ('mbar', 'hPa', 'Pa')!"
1279- )
1280- if isinstance (pressure_conversion_factor , (float , int )):
1281- if pressure_conversion_factor <= 0 :
1282- raise ValueError (
1283- "Argument 'pressure_conversion_factor' must be strictly positive!"
1284- )
1285- else :
1286- conversion_factor = pressure_conversion_factor
1287- if isinstance (pressure_conversion_factor , str ):
1288- if pressure_conversion_factor .lower () in ("mbar" , "hpa" ):
1289- conversion_factor = 100
1290- elif pressure_conversion_factor .lower () == "pa" :
1291- conversion_factor = 1
1292- else :
1279+ # Capture the user-supplied names before __validate_dictionary
1280+ # converts them to dicts, so they can drive auto-detection.
1281+ _input_dict = (
1282+ dictionary .upper () if isinstance (dictionary , str ) else None
1283+ )
1284+ _input_file = (
1285+ file .upper () if isinstance (file , str ) else None
1286+ )
1287+
1288+ # Validate format of user-supplied value (if any).
1289+ # When None, auto-detection runs after dictionary resolution.
1290+ if pressure_conversion_factor is not None :
1291+ if not isinstance (pressure_conversion_factor , (float , int , str )):
12931292 raise ValueError (
1294- "Argument 'pressure_conversion_factor' unit must be a standard pressure unit ('mbar', 'hPa', 'Pa')!"
1293+ "Argument 'pressure_conversion_factor' must be numeric or a standard pressure unit ('mbar', 'hPa', 'Pa')!"
12951294 )
1295+ if isinstance (pressure_conversion_factor , (float , int )):
1296+ if pressure_conversion_factor <= 0 :
1297+ raise ValueError (
1298+ "Argument 'pressure_conversion_factor' must be strictly positive!"
1299+ )
1300+ if isinstance (pressure_conversion_factor , str ):
1301+ if pressure_conversion_factor .lower () not in (
1302+ "mbar" ,
1303+ "hpa" ,
1304+ "pa" ,
1305+ ):
1306+ raise ValueError (
1307+ "Argument 'pressure_conversion_factor' unit must be a standard pressure unit ('mbar', 'hPa', 'Pa')!"
1308+ )
12961309
12971310 if isinstance (file , str ):
12981311 shortcut_map = self .__atm_type_file_to_function_map .get (type , {})
@@ -1325,6 +1338,32 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
13251338 )
13261339
13271340 dictionary = self .__validate_dictionary (file , dictionary )
1341+
1342+ # Determine the numeric conversion factor (pressure → Pa).
1343+ if pressure_conversion_factor is not None :
1344+ # User explicitly supplied a value — honour it.
1345+ if isinstance (pressure_conversion_factor , str ):
1346+ conversion_factor = (
1347+ 100
1348+ if pressure_conversion_factor .lower () in ("mbar" , "hpa" )
1349+ else 1
1350+ )
1351+ else :
1352+ conversion_factor = pressure_conversion_factor
1353+ else :
1354+ # Auto-detect. Primary source: known-model lookup table.
1355+ # Fallback: units attribute inside the file (handled inside
1356+ # get_pressure_levels_from_file when conversion_factor=None).
1357+ _hpa_dicts = {"ECMWF" , "ECMWF_V0" , "ERA5" , "MERRA2" }
1358+ _pa_files = {"GFS" , "NAM" , "RAP" , "HRRR" , "AIGFS" , "HIRESW" , "GEFS" }
1359+ if _input_dict in _hpa_dicts or _input_file in _hpa_dicts :
1360+ conversion_factor = 100
1361+ elif _input_file in _pa_files :
1362+ conversion_factor = 1
1363+ else :
1364+ # Unknown model or custom dict: read units from file.
1365+ conversion_factor = None
1366+
13281367 try :
13291368 fetch_function = self .__atm_type_file_to_function_map [type ][file ]
13301369 except KeyError :
@@ -1339,6 +1378,30 @@ def set_atmospheric_model( # pylint: disable=too-many-statements
13391378 )
13401379 else :
13411380 self .process_ensemble (dataset , dictionary , conversion_factor )
1381+
1382+ ground_pressure = self .pressure (self .elevation )
1383+ if not (30_000 <= ground_pressure <= 120_000 ):
1384+ if pressure_conversion_factor is None :
1385+ hint = (
1386+ "The unit was auto-detected from the file's pressure "
1387+ "level variable, but the result is still out of range. "
1388+ "Override by passing pressure_conversion_factor explicitly "
1389+ "('hPa' for ERA5/ECMWF files, 'Pa' for MERRA2 and online "
1390+ "forecast models such as GFS, NAM, RAP, HRRR)."
1391+ )
1392+ else :
1393+ hint = (
1394+ f"pressure_conversion_factor='{ pressure_conversion_factor } ' "
1395+ f"may be wrong. ERA5/ECMWF reanalysis files store pressure "
1396+ f"in hPa — use 'hPa'. MERRA2 and online forecast models "
1397+ f"(GFS, NAM, RAP, HRRR) store pressure in Pa — use 'Pa'."
1398+ )
1399+ warnings .warn (
1400+ f"Ground-level pressure is { ground_pressure :.0f} Pa, which is "
1401+ f"outside the expected range [30 000 Pa, 120 000 Pa]. { hint } " ,
1402+ UserWarning ,
1403+ stacklevel = 2 ,
1404+ )
13421405 case _: # pragma: no cover
13431406 raise ValueError (f"Unknown model type '{ type } '." )
13441407
0 commit comments