Validating a simulation involves three steps: register the observational datasets, matchup the simulation output against them, and generate statistics and an HTML report. Always create a new directory before running OceanVal for a new simulation, and run all commands from within it. Once you have reports for multiple simulations, you can also compare them side by side.
Register the observational datasets you want to validate against by specifying the location of the data files and any necessary metadata, using oceanval.add_point_comparison and oceanval.add_gridded_comparison.
Register a gridded (NetCDF) dataset by pointing OceanVal at a directory of observation files and saying whether the data is a climatology:
oceanval.add_gridded_comparison( name="oxygen", source="CMEMS", source_info="Gridded observations from the Copernicus Marine Environment Monitoring Service", short_name="oxygen concentration", model_variable="oxygen", obs_variable="O2_concentration", obs_path="/path/to/obs_data/", climatology=False, )
Required parameters:
namerequiredA name for the dataset, e.g. "temperature".
sourcerequiredThe source of the observational data, e.g. "CMEMS".
model_variablerequiredThe name of the model variable to compare against the observations.
obs_pathrequiredPath to the directory containing the observational data files.
obs_variableName of the variable in the observational files. If omitted, OceanVal assumes a single variable is present.
climatologyrequiredWhether the observational data is a climatology.
source_infoAdditional information about the source, e.g. publication details.
short_nameA short name for the observational variable, e.g. "temp".
short_titleA short title for plots, e.g. "Nitrate Concentration".
long_nameA long name for the variable, e.g. "sea surface temperature".
verticalWhether to carry out vertical validation. Defaults to False (surface only).
start / endFirst / last year of observations to use. Defaults to all available years.
obs_multiplierMultiplier applied to observational data, e.g. for unit conversion. Defaults to 1.0.
obs_adderValue added to observational data, e.g. 273.15 to convert Kelvin to Celsius. Defaults to 0.0.
recipeA built-in recipe dict, e.g. {"temperature": "woa23"}, providing standard metadata and file locations automatically.
threddsWhether obs_path is a remote OPeNDAP/THREDDS URL rather than a local file or directory. Defaults to False.
file_checkWhether to check that obs_path exists and its variables are valid. Defaults to True.
If you register the same variable separately for point and gridded data, give both the same short_name, long_name and short_title — plots and statistics need consistent labelling. Inconsistent labels raise an error.
Gridded data is converted to one of: a time series of multi-year monthly averages, a climatological monthly average, or a climatological annual average per grid cell.
The simulation output is always regridded to the observational grid.
Built-in recipe definitions make it easy to register standard observational datasets — especially useful for a standard climatology such as WOA23 or GLODAP, without manually specifying all the metadata.
oceanval.add_gridded_comparison( name="temperature", source="WOA23", model_variable="temp", recipe={"temperature": "woa23"}, start=2005, end=2014, climatology=True, )
This uses the built-in metadata and file locations for the WOA23 temperature climatology. recipe also works for salinity, oxygen, nitrate, phosphate, silicate, chlorophyll and pH — see all recipes. The underlying helper can also be used directly:
recipe = oceanval.parsers.find_recipe({"temperature": "woa23"}, start=2005, end=2014) print(recipe["source"], recipe["obs_variable"])
Browse the full recipe catalogue to see every supported observational dataset, with the exact call to use for each.
Register an in-situ dataset by pointing OceanVal at a CSV (or directory of CSVs) and naming the model variable to compare it against:
oceanval.add_point_comparison( name="nitrate", source="ICES", source_info="In-situ observations from the International Council for the Exploration of the Sea", short_name="nitrate concentration", model_variable="temp", obs_path="/path/to/obs_data/", )
Required parameters:
namerequiredA name for the dataset, e.g. "temperature" — used internally to keep track of things. Letters and numbers only.
sourcerequiredThe source of the observational data, e.g. "NOAA".
model_variablerequiredThe name of the model variable to compare against the observations.
obs_pathrequiredPath to a file or directory containing the observational data. If a directory, ensure it only contains files relevant to this variable — OceanVal recursively uses all NetCDF files inside it.
source_infoAdditional information about the source, e.g. publication details.
short_nameA short name for the observational variable, e.g. "temp".
short_titleA short title for plots, e.g. "Nitrate Concentration".
long_nameA long name for the variable, e.g. "sea surface temperature".
verticalWhether to carry out vertical validation. Defaults to False (surface only).
start / endFirst / last year of observations to use. Defaults to all available years.
obs_multiplierMultiplier applied to observational data, e.g. for unit conversion. Defaults to 1.0.
obs_adderValue added to observational data, e.g. 273.15 to convert Kelvin to Celsius. Defaults to 0.0.
binningSpatially bin data to a [lon_bin_size, lat_bin_size] resolution in degrees. Off by default.
name can be anything — it's only used internally to keep track of things and name files. Reports and plots use short_name, long_name and short_title for labelling, so set these for a better-looking report. You can only validate a variable using a single gridded and a single point dataset at a time.
Once your datasets are registered, pair the model output against them with oceanval.matchup:
oceanval.matchup( sim_dir="/path/to/simulation/output/", start=2000, end=2010, cores=4, lon_lim=[-80, 0], lat_lim=[20, 60], thickness="cell_thickness", )
Required parameters:
sim_dirrequiredPath to the directory containing the model simulation output files.
start / endrequiredFirst / last year of the simulation to use for validation.
coresNumber of CPU cores to use for parallel processing.
lon_lim / lat_limLongitude / latitude limits for the validation region, e.g. [-180, 180].
thicknessvertical only"z_level" or a variable name containing cell thickness — required for vertical validation.
n_dirs_downDirectory levels to search down for output files. Defaults to 2, assuming a YYYY/MM/ structure.
overwrite / askWhether to overwrite existing matchup files, and whether to confirm first. ask defaults to True.
cacheWhether to cache intermediate results. Defaults to False.
excludeStrings that should not appear in any simulation file paths.
requireStrings that must appear in a simulation file path for it to be included — useful when multiple simulations share a directory.
out_dirDirectory to save matchup files in. Defaults to the execution directory.
point_time_resTime resolution for point matchups. Defaults to ["year", "month", "day"]; set to ["month", "day"] to compare climatological output with observations.
n_checkNumber of files checked when identifying the file naming convention.
as_missingA float or [min, max] range of values to treat as missing in the model output.
strict_namesWhether to strictly enforce variable naming conventions. Defaults to True.
Simulation output must be in a single directory, or in subdirectories following a YYYY/MM/-style structure — subdirectories must contain only integers. If your structure differs, create symbolic links in a single directory. If multiple simulations share a directory, use require to filter file paths to the one you want.
Note: for monthly-resolution simulations, set point_time_res=["year", "month"] when matching up in-situ observations — otherwise day-of-year will almost never match and few matchups will be found.
Summing simulation output: to compare observations against the sum of multiple model variables, set something like "var1+var2+var3" as model_variable.
Behaviour depends on what's provided: year, month, day, depth.
vertical=True, OceanVal interpolates to all available depths; otherwise only the top 5 m is used.To ignore year information (e.g. comparing a 1-year simulation against multiple years of observations), set point_time_res=["month", "day"] in oceanval.matchup.
By default, in the directory where oceanval.matchup is run: oceanval_matchups/gridded (.nc files) and oceanval_matchups/point (.csv files). Model output is named "model" and observations "observation" in each file.
Once matched, compute statistics and generate plots with oceanval.validate, run from the same directory as the matchup step:
oceanval.validate()
lon_lim / lat_limLongitude / latitude limits for the validation region.
regionRegion being validated — currently "global" or "nwes" (Northwest European Shelf).
conciseWhether to generate a concise HTML summary page. Defaults to True.
fixed_scaleWhether to use a fixed colour scale for the seasonal plots, capping min/max to the 2nd/98th percentile. Defaults to False.
data_dir / out_dirWhere matchup data is read from / the report is written to. Default to the current directory.
This generates and opens an HTML page you can view in a web browser.
Once you have validation reports for different simulations, compare them with oceanval.compare, which summarises the differences between them:
oceanval.compare( model_dict={ "model_a": "/path/to/model_a", "model_b": "/path/to/model_b", }, view=True, ask=True, )
model_dict maps a short name for each model to its validation output directory. The HTML comparison report is written to oceanval_comparison/compare/_build/html/notebooks/comparison_seasonal.html.
Yes. OceanVal uses Jupyter notebooks to run validation calculations and generate plots. They live in the oceanval_report/notebooks directory of the report output — copy and edit them for a more customised validation. They're designed for internal use, so not especially user-friendly, but should be clear enough.