diff --git a/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/regression_test.ipynb b/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/regression_test.ipynb new file mode 100644 index 000000000..1b889e1b8 --- /dev/null +++ b/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/regression_test.ipynb @@ -0,0 +1,810 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CDAT Migration Regression Testing Notebook (`.nc` files)\n", + "\n", + "This notebook is used to perform regression testing between the development and\n", + "production versions of a diagnostic set.\n", + "\n", + "## How it works\n", + "\n", + "It compares the relative differences (%) between ref and test variables between\n", + "the dev and `main` branches.\n", + "\n", + "## How to use\n", + "\n", + "PREREQUISITE: The diagnostic set's netCDF stored in `.json` files in two directories\n", + "(dev and `main` branches).\n", + "\n", + "1. Make a copy of this notebook under `auxiliary_tools/cdat_regression_testing/`.\n", + "2. Run `mamba create -n cdat_regression_test -y -c conda-forge \"python<3.12\" xarray netcdf4 dask pandas matplotlib-base ipykernel`\n", + "3. Run `mamba activate cdat_regression_test`\n", + "4. Update `SET_DIR` and `SET_NAME` in the copy of your notebook.\n", + "5. Run all cells IN ORDER.\n", + "6. Review results for any outstanding differences (>=1e-5 relative tolerance).\n", + " - Debug these differences (e.g., bug in metrics functions, incorrect variable references, etc.)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup Code\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import glob\n", + "\n", + "import numpy as np\n", + "import xarray as xr\n", + "from e3sm_diags.derivations.derivations import DERIVED_VARIABLES\n", + "\n", + "\n", + "# TODO: Update SET_NAME and SET_DIR\n", + "SET_NAME = \"diurnal_cycle\"\n", + "SET_DIR = \"666-diurnal-cycle\"\n", + "\n", + "DEV_PATH = f\"/global/cfs/cdirs/e3sm/www/cdat-migration-fy24/{SET_DIR}/{SET_NAME}/**\"\n", + "DEV_GLOB = sorted(glob.glob(DEV_PATH + \"/*.nc\"))\n", + "DEV_NUM_FILES = len(DEV_GLOB)\n", + "\n", + "MAIN_PATH = f\"/global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/{SET_NAME}/**\"\n", + "MAIN_GLOB = sorted(glob.glob(MAIN_PATH + \"/*.nc\"))\n", + "MAIN_NUM_FILES = len(MAIN_GLOB)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "def _check_if_files_found():\n", + " if DEV_NUM_FILES == 0 or MAIN_NUM_FILES == 0:\n", + " raise IOError(\n", + " \"No files found at DEV_PATH and/or MAIN_PATH. \"\n", + " f\"Please check {DEV_PATH} and {MAIN_PATH}.\"\n", + " )\n", + "\n", + "\n", + "def _check_if_matching_filecount():\n", + " if DEV_NUM_FILES != MAIN_NUM_FILES:\n", + " raise IOError(\n", + " \"Number of files do not match at DEV_PATH and MAIN_PATH \"\n", + " f\"({DEV_NUM_FILES} vs. {MAIN_NUM_FILES}).\"\n", + " )\n", + "\n", + " print(f\"Matching file count ({DEV_NUM_FILES} and {MAIN_NUM_FILES}).\")\n", + "\n", + "\n", + "def _check_if_missing_files():\n", + " missing_count = 0\n", + "\n", + " for fp_main in MAIN_GLOB:\n", + " fp_dev = fp_main.replace(SET_DIR, \"main\")\n", + "\n", + " if fp_dev not in MAIN_GLOB:\n", + " print(f\"No production file found to compare with {fp_dev}!\")\n", + " missing_count += 1\n", + "\n", + " for fp_dev in DEV_GLOB:\n", + " fp_main = fp_main.replace(\"main\", SET_DIR)\n", + "\n", + " if fp_main not in DEV_GLOB:\n", + " print(f\"No development file found to compare with {fp_main}!\")\n", + " missing_count += 1\n", + "\n", + " print(f\"Number of files missing: {missing_count}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "def _get_relative_diffs():\n", + " # We are mainly focusing on relative tolerance here (in percentage terms).\n", + " atol = 0\n", + " rtol = 1e-5\n", + "\n", + " for fp_main in MAIN_GLOB:\n", + " if \"test.nc\" in fp_main or \"ref.nc\" in fp_main:\n", + " fp_dev = fp_main.replace(\"main\", SET_DIR)\n", + "\n", + " print(\"Comparing:\")\n", + " print(f\" * {fp_dev}\")\n", + " print(f\" * {fp_main}\")\n", + "\n", + " ds1 = xr.open_dataset(fp_dev)\n", + " ds2 = xr.open_dataset(fp_main)\n", + "\n", + " var_keys = [\n", + " \"PRECT_diurnal_cycmean\",\n", + " \"PRECT_diurnal_amplitude\",\n", + " \"PRECT_diurnal_phase\",\n", + " ]\n", + " for key in var_keys:\n", + " print(f\" * var_key: {key}\")\n", + "\n", + " dev_data = ds1[key].values\n", + " main_data = ds2[key].values\n", + "\n", + " if dev_data is None or main_data is None:\n", + " print(\" * Could not find variable key in the dataset(s)\")\n", + " continue\n", + "\n", + " try:\n", + " np.testing.assert_allclose(\n", + " dev_data,\n", + " main_data,\n", + " atol=atol,\n", + " rtol=rtol,\n", + " )\n", + " except (KeyError, AssertionError) as e:\n", + " print(f\" {e}\")\n", + " else:\n", + " print(f\" * All close and within relative tolerance ({rtol})\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Check for matching and equal number of files\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "_check_if_files_found()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Number of files missing: 0\n" + ] + } + ], + "source": [ + "_check_if_missing_files()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Matching file count (60 and 60).\n" + ] + } + ], + "source": [ + "_check_if_matching_filecount()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2 Compare the netCDF files between branches\n", + "\n", + "- Compare \"ref\" and \"test\" files\n", + "- \"diff\" files are ignored because getting relative diffs for these does not make sense (relative diff will be above tolerance)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-20S20N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-20S20N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-20S20N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-20S20N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-50S50N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-50S50N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-50S50N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-50S50N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-Amazon_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-Amazon_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-Amazon_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-Amazon_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-CONUS_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-CONUS_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-CONUS_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-CONUS_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-W_Pacific_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-W_Pacific_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-W_Pacific_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-W_Pacific_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-global_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-global_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-global_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-global_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-20S20N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-20S20N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-20S20N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-20S20N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-50S50N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-50S50N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-50S50N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-50S50N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-Amazon_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-Amazon_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-Amazon_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-Amazon_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-CONUS_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-CONUS_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-CONUS_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-CONUS_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-W_Pacific_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-W_Pacific_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-W_Pacific_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-W_Pacific_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-global_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-global_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-global_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-global_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-20S20N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-20S20N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-20S20N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-20S20N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-50S50N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-50S50N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-50S50N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-50S50N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-Amazon_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-Amazon_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-Amazon_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-Amazon_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-CONUS_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-CONUS_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-CONUS_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-CONUS_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-W_Pacific_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-W_Pacific_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-W_Pacific_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-W_Pacific_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-global_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-global_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-global_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-global_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-20S20N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-20S20N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-20S20N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-20S20N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-50S50N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-50S50N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-50S50N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-50S50N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-Amazon_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-Amazon_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-Amazon_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-Amazon_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-CONUS_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-CONUS_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-CONUS_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-CONUS_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-W_Pacific_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-W_Pacific_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-W_Pacific_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-W_Pacific_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-global_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-global_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-global_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-global_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-20S20N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-20S20N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-20S20N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-20S20N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-50S50N_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-50S50N_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-50S50N_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-50S50N_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-Amazon_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-Amazon_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-Amazon_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-Amazon_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-CONUS_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-CONUS_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-CONUS_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-CONUS_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-W_Pacific_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-W_Pacific_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-W_Pacific_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-W_Pacific_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global_ref.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global_ref.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global_test.nc\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global_test.nc\n", + " * var_key: PRECT_diurnal_cycmean\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_amplitude\n", + " * All close and within relative tolerance (1e-05)\n", + " * var_key: PRECT_diurnal_phase\n", + " * All close and within relative tolerance (1e-05)\n" + ] + } + ], + "source": [ + "_get_relative_diffs()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Results\n", + "\n", + "- All files are within rtol 1e-05.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "cdat_regression_test", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/regression_test_png.ipynb b/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/regression_test_png.ipynb new file mode 100644 index 000000000..083ab37d4 --- /dev/null +++ b/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/regression_test_png.ipynb @@ -0,0 +1,399 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CDAT Migration Regression Testing Notebook (`.png` files)\n", + "\n", + "This notebook is used to perform regression testing between the development and\n", + "production versions of a diagnostic set.\n", + "\n", + "## How to use\n", + "\n", + "PREREQUISITE: The diagnostic set's netCDF stored in `.json` files in two directories\n", + "(dev and `main` branches).\n", + "\n", + "1. Make a copy of this notebook under `auxiliary_tools/cdat_regression_testing/`.\n", + "2. Run `mamba create -n cdat_regression_test -y -c conda-forge \"python<3.12\" xarray netcdf4 dask pandas matplotlib-base ipykernel`\n", + "3. Run `mamba activate cdat_regression_test`\n", + "4. Update `SET_DIR` and `SET_NAME` in the copy of your notebook.\n", + "5. Run all cells IN ORDER.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup Code\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "import glob\n", + "\n", + "from auxiliary_tools.cdat_regression_testing.utils import get_image_diffs\n", + "\n", + "SET_NAME = \"diurnal_cycle\"\n", + "SET_DIR = \"666-diurnal-cycle\"\n", + "\n", + "DEV_PATH = f\"/global/cfs/cdirs/e3sm/www/cdat-migration-fy24/{SET_DIR}/{SET_NAME}/**\"\n", + "DEV_GLOB = sorted(glob.glob(DEV_PATH + \"/*.png\"))\n", + "DEV_NUM_FILES = len(DEV_GLOB)\n", + "\n", + "MAIN_PATH = f\"/global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/{SET_NAME}/**\"\n", + "MAIN_GLOB = sorted(glob.glob(MAIN_PATH + \"/*.png\"))\n", + "MAIN_NUM_FILES = len(MAIN_GLOB)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "def _check_if_files_found():\n", + " if DEV_NUM_FILES == 0 or MAIN_NUM_FILES == 0:\n", + " raise IOError(\n", + " \"No files found at DEV_PATH and/or MAIN_PATH. \"\n", + " f\"Please check {DEV_PATH} and {MAIN_PATH}.\"\n", + " )\n", + "\n", + "\n", + "def _check_if_matching_filecount():\n", + " if DEV_NUM_FILES != MAIN_NUM_FILES:\n", + " raise IOError(\n", + " \"Number of files do not match at DEV_PATH and MAIN_PATH \"\n", + " f\"({DEV_NUM_FILES} vs. {MAIN_NUM_FILES}).\"\n", + " )\n", + "\n", + " print(f\"Matching file count ({DEV_NUM_FILES} and {MAIN_NUM_FILES}).\")\n", + "\n", + "\n", + "def _check_if_missing_files():\n", + " missing_count = 0\n", + "\n", + " for fp_main in MAIN_GLOB:\n", + " fp_dev = fp_main.replace(SET_DIR, \"main-diurnal-cycle\")\n", + "\n", + " if fp_dev not in MAIN_GLOB:\n", + " print(f\"No production file found to compare with {fp_dev}!\")\n", + " missing_count += 1\n", + "\n", + " for fp_dev in DEV_GLOB:\n", + " fp_main = fp_main.replace(\"main-diurnal-cycle\", SET_DIR)\n", + "\n", + " if fp_main not in DEV_GLOB:\n", + " print(f\"No development file found to compare with {fp_main}!\")\n", + " missing_count += 1\n", + "\n", + " print(f\"Number of files missing: {missing_count}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Check for matching and equal number of files\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "_check_if_files_found()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "Number of files missing: 60\n" + ] + } + ], + "source": [ + "_check_if_missing_files()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "ename": "OSError", + "evalue": "Number of files do not match at DEV_PATH and MAIN_PATH (60 vs. 30).", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mOSError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[17], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43m_check_if_matching_filecount\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[14], line 11\u001b[0m, in \u001b[0;36m_check_if_matching_filecount\u001b[0;34m()\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_check_if_matching_filecount\u001b[39m():\n\u001b[1;32m 10\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m DEV_NUM_FILES \u001b[38;5;241m!=\u001b[39m MAIN_NUM_FILES:\n\u001b[0;32m---> 11\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mIOError\u001b[39;00m(\n\u001b[1;32m 12\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNumber of files do not match at DEV_PATH and MAIN_PATH \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 13\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m(\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mDEV_NUM_FILES\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m vs. \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mMAIN_NUM_FILES\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m).\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 14\u001b[0m )\n\u001b[1;32m 16\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMatching file count (\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mDEV_NUM_FILES\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mMAIN_NUM_FILES\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m).\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mOSError\u001b[0m: Number of files do not match at DEV_PATH and MAIN_PATH (60 vs. 30)." + ] + } + ], + "source": [ + "_check_if_matching_filecount()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2 Compare the plots between branches\n", + "\n", + "- Compare \"ref\" and \"test\" files\n", + "- \"diff\" files are ignored because getting relative diffs for these does not make sense (relative diff will be above tolerance)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-global.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-global.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-global.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-global.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png\n", + " * Plots are identical\n" + ] + } + ], + "source": [ + "for main_path, dev_path in zip(MAIN_GLOB, DEV_GLOB):\n", + " print(\"Comparing:\")\n", + " print(f\" * {main_path}\")\n", + " print(f\" * {dev_path}\")\n", + "\n", + " get_image_diffs(dev_path, main_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Results\n", + "\n", + "All plots are identical\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "cdat_regression_test", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/run.cfg b/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/run.cfg new file mode 100644 index 000000000..fb5fadd36 --- /dev/null +++ b/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/run.cfg @@ -0,0 +1,10 @@ +[#] +sets = ["diurnal_cycle"] +case_id = "TRMM-3B43v-7_3hr" +variables = ["PRECT"] +ref_name = "TRMM-3B43v-7_3hr" +# seasons = ["ANN", "DJF", "MAM", "JJA", "SON"] +seasons = ["ANN"] +# regions = ["CONUS", "20S20N", "W_Pacific", "Amazon","global","50S50N"] +regions = ["20S20N"] +reference_name = "TRMM-3B43v-7" diff --git a/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/run_script.py b/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/run_script.py new file mode 100644 index 000000000..b0028b999 --- /dev/null +++ b/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/run_script.py @@ -0,0 +1,12 @@ +# %% +# python -m auxiliary_tools.cdat_regression_testing.666-diurnal-cycle.run_script +from auxiliary_tools.cdat_regression_testing.base_run_script import run_set + +SET_NAME = "diurnal_cycle" +SET_DIR = "666-diurnal-cycle" +CFG_PATH: str | None = None +# CFG_PATH: str | None = "/global/u2/v/vo13/E3SM-Project/e3sm_diags/auxiliary_tools/cdat_regression_testing/666-diurnal-cycle/run.cfg" +MULTIPROCESSING = True + +# %% +run_set(SET_NAME, SET_DIR, CFG_PATH, MULTIPROCESSING) diff --git a/auxiliary_tools/cdat_regression_testing/template_cdat_regression_test_png.ipynb b/auxiliary_tools/cdat_regression_testing/template_cdat_regression_test_png.ipynb new file mode 100644 index 000000000..373dbf5b6 --- /dev/null +++ b/auxiliary_tools/cdat_regression_testing/template_cdat_regression_test_png.ipynb @@ -0,0 +1,394 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CDAT Migration Regression Testing Notebook (`.png` files)\n", + "\n", + "This notebook is used to perform regression testing between the development and\n", + "production versions of a diagnostic set.\n", + "\n", + "## How to use\n", + "\n", + "PREREQUISITE: The diagnostic set's netCDF stored in `.json` files in two directories\n", + "(dev and `main` branches).\n", + "\n", + "1. Make a copy of this notebook under `auxiliary_tools/cdat_regression_testing/`.\n", + "2. Run `mamba create -n cdat_regression_test -y -c conda-forge \"python<3.12\" xarray netcdf4 dask pandas matplotlib-base ipykernel`\n", + "3. Run `mamba activate cdat_regression_test`\n", + "4. Update `SET_DIR` and `SET_NAME` in the copy of your notebook.\n", + "5. Run all cells IN ORDER.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup Code\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "import glob\n", + "\n", + "from auxiliary_tools.cdat_regression_testing.utils import get_image_diffs\n", + "\n", + "SET_NAME = \"diurnal_cycle\"\n", + "SET_DIR = \"666-diurnal-cycle\"\n", + "\n", + "DEV_PATH = f\"/global/cfs/cdirs/e3sm/www/cdat-migration-fy24/{SET_DIR}/{SET_NAME}/**\"\n", + "DEV_GLOB = sorted(glob.glob(DEV_PATH + \"/*.png\"))\n", + "DEV_NUM_FILES = len(DEV_GLOB)\n", + "\n", + "MAIN_PATH = f\"/global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/{SET_NAME}/**\"\n", + "MAIN_GLOB = sorted(glob.glob(MAIN_PATH + \"/*.png\"))\n", + "MAIN_NUM_FILES = len(MAIN_GLOB)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "def _check_if_files_found():\n", + " if DEV_NUM_FILES == 0 or MAIN_NUM_FILES == 0:\n", + " raise IOError(\n", + " \"No files found at DEV_PATH and/or MAIN_PATH. \"\n", + " f\"Please check {DEV_PATH} and {MAIN_PATH}.\"\n", + " )\n", + "\n", + "\n", + "def _check_if_matching_filecount():\n", + " if DEV_NUM_FILES != MAIN_NUM_FILES:\n", + " raise IOError(\n", + " \"Number of files do not match at DEV_PATH and MAIN_PATH \"\n", + " f\"({DEV_NUM_FILES} vs. {MAIN_NUM_FILES}).\"\n", + " )\n", + "\n", + " print(f\"Matching file count ({DEV_NUM_FILES} and {MAIN_NUM_FILES}).\")\n", + "\n", + "\n", + "def _check_if_missing_files():\n", + " missing_count = 0\n", + "\n", + " for fp_main in MAIN_GLOB:\n", + " fp_dev = fp_main.replace(SET_DIR, \"main-diurnal-cycle\")\n", + "\n", + " if fp_dev not in MAIN_GLOB:\n", + " print(f\"No production file found to compare with {fp_dev}!\")\n", + " missing_count += 1\n", + "\n", + " for fp_dev in DEV_GLOB:\n", + " fp_main = fp_main.replace(\"main-diurnal-cycle\", SET_DIR)\n", + "\n", + " if fp_main not in DEV_GLOB:\n", + " print(f\"No development file found to compare with {fp_main}!\")\n", + " missing_count += 1\n", + "\n", + " print(f\"Number of files missing: {missing_count}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Check for matching and equal number of files\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "_check_if_files_found()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "No development file found to compare with /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png!\n", + "Number of files missing: 60\n" + ] + } + ], + "source": [ + "_check_if_missing_files()" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "ename": "OSError", + "evalue": "Number of files do not match at DEV_PATH and MAIN_PATH (60 vs. 30).", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mOSError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[17], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43m_check_if_matching_filecount\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "Cell \u001b[0;32mIn[14], line 11\u001b[0m, in \u001b[0;36m_check_if_matching_filecount\u001b[0;34m()\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_check_if_matching_filecount\u001b[39m():\n\u001b[1;32m 10\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m DEV_NUM_FILES \u001b[38;5;241m!=\u001b[39m MAIN_NUM_FILES:\n\u001b[0;32m---> 11\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mIOError\u001b[39;00m(\n\u001b[1;32m 12\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNumber of files do not match at DEV_PATH and MAIN_PATH \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 13\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m(\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mDEV_NUM_FILES\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m vs. \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mMAIN_NUM_FILES\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m).\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 14\u001b[0m )\n\u001b[1;32m 16\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mMatching file count (\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mDEV_NUM_FILES\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m and \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mMAIN_NUM_FILES\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m).\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n", + "\u001b[0;31mOSError\u001b[0m: Number of files do not match at DEV_PATH and MAIN_PATH (60 vs. 30)." + ] + } + ], + "source": [ + "_check_if_matching_filecount()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2 Compare the plots between branches\n", + "\n", + "- Compare \"ref\" and \"test\" files\n", + "- \"diff\" files are ignored because getting relative diffs for these does not make sense (relative diff will be above tolerance)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-ANN-global.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-DJF-global.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-JJA-global.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-MAM-global.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-20S20N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-20S20N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-50S50N.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-50S50N.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-Amazon.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-Amazon.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-CONUS.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-CONUS.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-W_Pacific.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-W_Pacific.png\n", + " * Plots are identical\n", + "Comparing:\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/main-diurnal/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png\n", + " * /global/cfs/cdirs/e3sm/www/cdat-migration-fy24/666-diurnal-cycle/diurnal_cycle/TRMM-3B43v-7_3hr/TRMM-3B43v-7_3hr-PRECT-SON-global.png\n", + " * Plots are identical\n" + ] + } + ], + "source": [ + "for main_path, dev_path in zip(MAIN_GLOB, DEV_GLOB):\n", + " print(\"Comparing:\")\n", + " print(f\" * {main_path}\")\n", + " print(f\" * {dev_path}\")\n", + "\n", + " get_image_diffs(dev_path, main_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Results\n", + "\n", + "All plots are identical\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "cdat_regression_test", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/auxiliary_tools/cdat_regression_testing/utils.py b/auxiliary_tools/cdat_regression_testing/utils.py index b23658ba7..2f8fa69ae 100644 --- a/auxiliary_tools/cdat_regression_testing/utils.py +++ b/auxiliary_tools/cdat_regression_testing/utils.py @@ -1,4 +1,5 @@ import math +import os from typing import List import pandas as pd @@ -163,7 +164,7 @@ def get_num_metrics_above_diff_thres( ) -def get_image_diffs(actual_path: str, expected_path: str): +def get_image_diffs(actual_path: str, expected_path: str) -> str | None: """Get the diffs between two images. This function is useful for comparing two datasets that can't be compared @@ -183,10 +184,28 @@ def get_image_diffs(actual_path: str, expected_path: str): expected_png = Image.open(expected_path).convert("RGB") diff = ImageChops.difference(actual_png, expected_png) - draw = ImageDraw.Draw(diff) - (left, upper, right, lower) = diff.getbbox() - draw.rectangle(((left, upper), (right, lower)), outline="red") - diff_path = actual_path.replace("actual", "diff") + try: + (left, upper, right, lower) = diff.getbbox() + except TypeError as e: + if "cannot unpack non-iterable NoneType object" in str(e): + print(" * Plots are identical") + + return None + else: + draw.rectangle(((left, upper), (right, lower)), outline="red") + + # Create the diff directory. + split_actual_path = actual_path.split("/") + split_actual_path[-2] = f"{split_actual_path[-2]}_diff" + actual_dir_path = ("/").join(split_actual_path[0:-1]) + os.makedirs(actual_dir_path, exist_ok=True) + + # Save the png file to the diff directory. + diff_path = ("/").join(split_actual_path) diff.save(diff_path) + + print(f" * Difference path {diff_path}") + + return diff_path diff --git a/e3sm_diags/driver/diurnal_cycle_driver.py b/e3sm_diags/driver/diurnal_cycle_driver.py index 5dc252816..83f2a66fc 100644 --- a/e3sm_diags/driver/diurnal_cycle_driver.py +++ b/e3sm_diags/driver/diurnal_cycle_driver.py @@ -1,14 +1,15 @@ from __future__ import annotations -import os -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Literal -import cdms2 +import xarray as xr -import e3sm_diags -from e3sm_diags.driver import utils +from e3sm_diags.driver.utils.dataset_xr import Dataset +from e3sm_diags.driver.utils.diurnal_cycle_xr import composite_diurnal_cycle +from e3sm_diags.driver.utils.io import _get_output_filename_filepath +from e3sm_diags.driver.utils.regrid import _apply_land_sea_mask, _subset_on_region from e3sm_diags.logger import custom_logger -from e3sm_diags.plot import plot +from e3sm_diags.plot.diurnal_cycle_plot import plot as plot_func logger = custom_logger(__name__) @@ -22,94 +23,109 @@ def run_diag(parameter: DiurnalCycleParameter) -> DiurnalCycleParameter: ref_name = getattr(parameter, "ref_name", "") regions = parameter.regions - test_data = utils.dataset.Dataset(parameter, test=True) - ref_data = utils.dataset.Dataset(parameter, ref=True) - - for season in seasons: - # Get the name of the data, appended with the years averaged. - parameter.test_name_yrs = utils.general.get_name_and_yrs( - parameter, test_data, season - ) - parameter.ref_name_yrs = utils.general.get_name_and_yrs( - parameter, ref_data, season - ) - - # Get land/ocean fraction for masking. - try: - land_frac = test_data.get_climo_variable("LANDFRAC", season) - ocean_frac = test_data.get_climo_variable("OCNFRAC", season) - except Exception: - mask_path = os.path.join( - e3sm_diags.INSTALL_PATH, "acme_ne30_ocean_land_mask.nc" - ) - with cdms2.open(mask_path) as f: - land_frac = f("LANDFRAC") - ocean_frac = f("OCNFRAC") - - for var in variables: - logger.info("Variable: {}".format(var)) - test = test_data.get_climo_variable(var, season) - ref = ref_data.get_climo_variable(var, season) - - parameter.var_id = var - parameter.viewer_descr[var] = ( - test.long_name - if hasattr(test, "long_name") - else "No long_name attr in test data." - ) + test_ds = Dataset(parameter, data_type="test") + ref_ds = Dataset(parameter, data_type="ref") + + for var_key in variables: + logger.info("Variable: {}".format(var_key)) + parameter.var_id = var_key + + for season in seasons: + parameter._set_name_yrs_attrs(test_ds, ref_ds, season) + + ds_land_sea_mask: xr.Dataset = test_ds._get_land_sea_mask(season) + + ds_test = test_ds.get_climo_dataset(var_key, season) + ds_ref = ref_ds.get_climo_dataset(var_key, season) for region in regions: - test_domain = utils.general.select_region( - region, test, land_frac, ocean_frac, parameter - ) - ref_domain = utils.general.select_region( - region, ref, land_frac, ocean_frac, parameter + if "land" in region or "ocean" in region: + test_domain = _apply_land_sea_mask( + ds_test, + ds_land_sea_mask, + var_key, + region, # type: ignore + parameter.regrid_tool, + parameter.regrid_method, + ) + + ref_domain = _apply_land_sea_mask( + ds_ref, + ds_land_sea_mask, + var_key, + region, # type: ignore + parameter.regrid_tool, + parameter.regrid_method, + ) + else: + test_domain = ds_test.copy() + ref_domain = ds_ref.copy() + + test_domain = _subset_on_region(test_domain, var_key, region) + ref_domain = _subset_on_region(ref_domain, var_key, region) + + parameter.viewer_descr[var_key] = ds_test[var_key].attrs.get( + "long_name", "No long_name attr in test data." ) - - parameter.output_file = "-".join([ref_name, var, season, region]) + parameter.output_file = "-".join([ref_name, var_key, season, region]) parameter.main_title = str( - " ".join([var, "Diurnal Cycle ", season, region]) + " ".join([var_key, "Diurnal Cycle ", season, region]) ) ( test_cmean, test_amplitude, test_maxtime, - ) = utils.diurnal_cycle.composite_diurnal_cycle(test_domain, season) + ) = composite_diurnal_cycle( + test_domain, var_key, season + ) # type: ignore ( ref_cmean, ref_amplitude, ref_maxtime, - ) = utils.diurnal_cycle.composite_diurnal_cycle(ref_domain, season) + ) = composite_diurnal_cycle( + ref_domain, var_key, season + ) # type: ignore + parameter.var_region = region - plot( - parameter.current_set, + + plot_func( test_maxtime, test_amplitude, ref_maxtime, ref_amplitude, parameter, ) - utils.general.save_ncfiles( - parameter.current_set, - test_cmean, - ref_cmean, - None, - parameter, - ) - utils.general.save_ncfiles( - parameter.current_set, - test_amplitude, - ref_amplitude, - None, - parameter, + + ds_out_test = xr.Dataset( + data_vars={ + test_cmean.name: test_cmean, + test_amplitude.name: test_amplitude, + test_maxtime.name: test_maxtime, + } ) - utils.general.save_ncfiles( - parameter.current_set, - test_maxtime, - ref_maxtime, - None, - parameter, + ds_out_ref = xr.Dataset( + data_vars={ + ref_cmean.name: ref_cmean, + ref_amplitude.name: ref_amplitude, + ref_maxtime.name: ref_maxtime, + } ) + _write_vars_to_netcdf(parameter, var_key, ds_out_test, "test") + _write_vars_to_netcdf(parameter, var_key, ds_out_ref, "ref") + return parameter + + +def _write_vars_to_netcdf( + parameter: DiurnalCycleParameter, + var_key: str, + ds: xr.Dataset, + data_type: Literal["test", "ref"], +): + _, filepath = _get_output_filename_filepath(parameter, data_type) + + ds.to_netcdf(filepath) + + logger.info(f"'{var_key}' {data_type} variable output saved in: {filepath}") diff --git a/e3sm_diags/driver/utils/diurnal_cycle_xr.py b/e3sm_diags/driver/utils/diurnal_cycle_xr.py new file mode 100644 index 000000000..cf4a1a6ea --- /dev/null +++ b/e3sm_diags/driver/utils/diurnal_cycle_xr.py @@ -0,0 +1,288 @@ +from __future__ import annotations + +from typing import Tuple + +import numpy as np +import numpy.ma as ma +import xarray as xr +import xcdat as xc + +from e3sm_diags.driver.utils.climo_xr import CLIMO_CYCLE_MAP, ClimoFreq +from e3sm_diags.logger import custom_logger + +logger = custom_logger(__name__) + +SEASON_IDX = { + "01": [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "02": [0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "03": [0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "04": [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], + "05": [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], + "06": [0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], + "07": [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], + "08": [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0], + "09": [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0], + "10": [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0], + "11": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0], + "12": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + "DJF": [1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + "MAM": [0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0], + "JJA": [0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0], + "SON": [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0], + "ANN": [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], +} + + +def composite_diurnal_cycle( + ds: xr.Dataset, var_key: str, season: ClimoFreq, fft: bool = True +) -> Tuple[xr.DataArray, np.ndarray] | Tuple[xr.DataArray, xr.DataArray, xr.DataArray]: + """Compute the composite diurnal cycle for a variable for a given season. + + TODO: Add unit tests for this function. + + Parameters + ---------- + ds : xr.Dataset + The dataset containing the variable. + var_key : str + The key of the variable. + season : ClimoFreq + The season for the climatology. + fft : bool, optional + Calculate using Fast Fourier transform, by default True. + + Returns + ------- + Tuple[xr.DataArray, np.ndarray] | Tuple[xr.DataArray, xr.DataArray, xr.DataArray] + Either a tuple containing the DataArray for the diurnal cycle of the variable + and the time coordinates as LST, or a tuple of three DataArrays for mean, + amplitudes, and times-of-maximum of the first Fourier harmonic component + (if ``fft=True``). + """ + var = ds[var_key].copy() + + lat, lon = _get_lat_and_lon(var) + time = _get_time(ds, var_key) + time_freq, start_time = _get_time_freq_and_start_time(time) + + site = lat is None and lon is None + if site: + nlat = 1 + nlon = 1 + + lat = [lat] # type: ignore + lon = [lon] # type: ignore + else: + nlat = len(lat) # type: ignore + nlon = len(lon) # type: ignore + + var_diurnal = _calc_var_diurnal(var, season, time, time_freq, site) + + # Convert GMT to LST + nt = time_freq + lst = np.zeros((nt, nlat, nlon)) + for it, itime in enumerate(np.arange(0, 24, 24 / nt)): + for ilon in range(nlon): + lst[it, :, ilon] = (itime + start_time + lon[ilon] / 360 * 24) % 24 # type: ignore + + # Compute mean, amplitude and max time of the first three Fourier components. + if not fft: + return var_diurnal, lst + else: + cycmean, maxvalue, tmax = _fft_all_grid(var_diurnal, lst) + + amplitude_data = np.zeros((nlat, nlon)) + amplitude_data[:, :] = maxvalue[0] + amplitude = xr.DataArray( + name="PRECT_diurnal_amplitude", + data=amplitude_data, + coords={lat.name: lat, lon.name: lon}, # type: ignore + attrs={ + "longname": "Amplitude of diurnal cycle of PRECT", + "units": var.units, + }, + ) + + maxtime_data = np.zeros((nlat, nlon)) + maxtime_data[:, :] = tmax[0] + maxtime = xr.DataArray( + name="PRECT_diurnal_phase", + data=maxtime_data, + coords={lat.name: lat, lon.name: lon}, # type: ignore + attrs={ + "longname": "Phase of diurnal cycle of PRECT", + "units": "hour", + }, + ) + + cmean_data = np.zeros((nlat, nlon)) + cmean_data[:, :] = cycmean + cmean = xr.DataArray( + name="PRECT_diurnal_cycmean", + data=cmean_data, + coords={lat.name: lat, lon.name: lon}, # type: ignore + attrs={ + "longname": "Mean of diurnal cycle of PRECT", + "units": "hour", + }, + ) + + return cmean, amplitude, maxtime + + +def _calc_var_diurnal( + var: xr.DataArray, season: str, time: xr.DataArray, time_freq: int, site: bool +) -> xr.DataArray: + cycle = CLIMO_CYCLE_MAP.get(season, [season]) + ncycle = len(cycle) + + # var_diurnal has shape i.e. (ncycle, ntimesteps, [lat,lon]) for lat lon data + var_diurnal = ma.zeros([ncycle] + [time_freq] + list(np.shape(var))[1:]) + + for n in range(ncycle): + # Get time index for each month/season. + time_idxs = [] + + for time_idx in range(len(time)): + month_idx = (time[time_idx].dt.month - 1).item() + cycle_idx = cycle[n] + + time_idxs.append(SEASON_IDX[cycle_idx][month_idx]) + + time_idxs = np.array(time_idxs, dtype=int).nonzero() # type: ignore + + var_reshape = np.reshape( + var[time_idxs].values, + (int(var[time_idxs].shape[0] / time_freq), time_freq) + + var[time_idxs].shape[1:], + ) + var_diurnal[n,] = ma.average( + var_reshape, + axis=0, + ) + + if not site: + var_diurnal = np.squeeze(var_diurnal) + + return var_diurnal + + +def _get_time(ds: xr.Dataset, var_key: str) -> xr.DataArray: + ds_decoded = xr.decode_cf(ds, decode_times=True, use_cftime=True) + + try: + time = xc.get_dim_coords(ds_decoded, axis="T") + except (ValueError, KeyError): + raise KeyError( + f"This variable ({var_key}) does not have a time axis. " + "Climatology cannot be run on this variable." + ) + + return time + + +def _get_time_freq_and_start_time(time: xr.DataArray) -> Tuple[int, int]: + time_0 = time[0].dt.hour + time[0].dt.minute / 60 + time[0].dt.second / 3600 + time_1 = time[1].dt.hour + time[1].dt.minute / 60 + time[1].dt.second / 3600 + + time_freq = int(24 / (time_1 - time_0)) + start_time = time_0 + + logger.info(f"start_time {time.values[0]} {start_time.item()}") + logger.info(f"var_time_freq={time_freq}") + + return time_freq, start_time + + +def _get_lat_and_lon( + var: xr.DataArray, +) -> Tuple[xr.DataArray | None, xr.DataArray | None]: + lat = None + lon = None + + try: + lat = xc.get_dim_coords(var, axis="Y") + except (ValueError, KeyError): + pass + + try: + lon = xc.get_dim_coords(var, axis="X") + except (ValueError, KeyError): + pass + + return lat, lon + + +def _fft_all_grid( + var_diurnal: xr.DataArray, lst_time: np.ndarray +) -> Tuple[np.ndarray, np.ndarray, np.ndarray]: + """Calculate Fast Fourier transform. + + This version of fastFT does all gridpoints at once. It uses a numerical + Python function to compute a FAST Fourier transform, which should give the + same result as a simple SLOW Fourier integration via the trapezoidal rule. + + Do NOT detrend the time series first, in order to retain the "sawtooth" + frequency implied by the inumpy.t length of the time series (e.g. the + 24-hour period from a composite-diurnal cycle). + + On inumpy.t: x[k,i,j] = values at each gridpoint (i,j) for N times (k), + - e.g. N = 8 for a 3-hr composite-diurnal cycle t[k,i,j] = timepoints + at each gridpoint (i,j) for N times (k), e.g. Local Standard Times + + On output: c[i,j] = mean value at each gridpoint (i,j) in the time series + ("zeroth" term in Fourier series) + - maxvalue[n,i,j] = amplitude at each gridpoint (i,j) for each + Fourier harmonic (n) + - tmax [n,i,j] = time of maximum at each gridpoint (i,j) for each + Fourier harmonic (n) + + Source: Curt Covey, PCMDI/LLNL (December 2016) + + Parameters + ---------- + var_diurnal : xr.DataArray + The diurnal cycle for the variable. + lst_time : np.ndarray + A numpy array of LST time values. + + Returns + ------- + Tuple[np.ndarray, np.ndarray, np.ndarray] + A tuple of numpy arrays for mean, amplitudes, and times-of-maximum of + the first three Fourier harmonic components of the diurnal cycle of a + variable. + """ + # Creating output arrays + if len(var_diurnal.shape) == 1: + nx = 1 + ny = 1 + else: + nx = var_diurnal.shape[1] + ny = var_diurnal.shape[2] + + # time of maximum for nth component (n=0 => diurnal, n=1 => semi...) + tmax = np.zeros((3, nx, ny)) + # value of maximum for nth component (= 1/2 peak-to-peak amplitude) + maxvalue = np.zeros((3, nx, ny)) + + logger.info( + "Calling numpy FFT function and converting from complex-valued FFT to real-valued amplitude and phase" + ) + X = np.fft.ifft(var_diurnal, axis=0) + logger.info("FFT output shape={}".format(X.shape)) + + # Converting from complex-valued FFT to real-valued amplitude and phase + a = X.real + b = X.imag + S = np.sqrt(a**2 + b**2) + c = S[0] # Zeroth harmonic = mean-value "constant term" in Fourier series. + for n in range(3): + # Adding first + last terms, second + second-to-last, ... + maxvalue[n] = S[n + 1] + S[-n - 1] + tmax[n] = np.arctan2(b[n + 1], a[n + 1]) + tmax[n] = tmax[n] * 12.0 / (np.pi * (n + 1)) # Radians to hours + tmax[n] = tmax[n] + lst_time[0] # GMT to LST + tmax[n] = tmax[n] % (24 / (n + 1)) + + return c, maxvalue, tmax diff --git a/e3sm_diags/driver/utils/io.py b/e3sm_diags/driver/utils/io.py index 35f867ad3..df9bed067 100644 --- a/e3sm_diags/driver/utils/io.py +++ b/e3sm_diags/driver/utils/io.py @@ -119,15 +119,12 @@ def _write_vars_to_netcdf( def _write_to_netcdf( - parameter, + parameter: CoreParameter, var: xr.DataArray, var_key: str, data_type: Literal["test", "ref", "diff"], ): - dir_path = _get_output_dir(parameter) - filename = f"{parameter.output_file}_{data_type}.nc" - - filepath = os.path.join(dir_path, filename) + filename, filepath = _get_output_filename_filepath(parameter, data_type) var.to_netcdf(filepath) @@ -136,6 +133,15 @@ def _write_to_netcdf( return filename +def _get_output_filename_filepath(parameter: CoreParameter, data_type: str): + dir_path = _get_output_dir(parameter) + filename = f"{parameter.output_file}_{data_type}.nc" + + filepath = os.path.join(dir_path, filename) + + return filename, filepath + + def _write_vars_to_single_netcdf( parameter: CoreParameter, var_key, diff --git a/e3sm_diags/driver/utils/regrid.py b/e3sm_diags/driver/utils/regrid.py index 64bad7875..98e30a619 100644 --- a/e3sm_diags/driver/utils/regrid.py +++ b/e3sm_diags/driver/utils/regrid.py @@ -301,16 +301,22 @@ def _subset_on_region(ds: xr.Dataset, var_key: str, region: str) -> xr.Dataset: ds_new = ds.copy() - if lat is not None: - lat_dim = xc.get_dim_keys(ds[var_key], axis="Y") - ds_new = ds_new.sortby(lat_dim) - ds_new = ds_new.sel({f"{lat_dim}": slice(*lat)}) - if lon is not None: lon_dim = xc.get_dim_keys(ds[var_key], axis="X") ds_new = ds_new.sortby(lon_dim) + + # TODO: Add a unit test for this + is_lon_axis_diff = lon[0] < 0 and ds_new[lon_dim].values[0] >= 0 + if is_lon_axis_diff: + ds_new = xc.swap_lon_axis(ds_new, to=(-180, 180)) + ds_new = ds_new.sel({f"{lon_dim}": slice(*lon)}) + if lat is not None: + lat_dim = xc.get_dim_keys(ds[var_key], axis="Y") + ds_new = ds_new.sortby(lat_dim) + ds_new = ds_new.sel({f"{lat_dim}": slice(*lat)}) + return ds_new diff --git a/e3sm_diags/plot/cartopy/diurnal_cycle_plot.py b/e3sm_diags/plot/cartopy/diurnal_cycle_plot.py deleted file mode 100644 index b1073af88..000000000 --- a/e3sm_diags/plot/cartopy/diurnal_cycle_plot.py +++ /dev/null @@ -1,322 +0,0 @@ -from __future__ import print_function - -import os - -import cartopy.crs as ccrs -import cartopy.feature as cfeature -import cdutil -import matplotlib -import numpy as np -import numpy.ma as ma -from cartopy.mpl.ticker import LatitudeFormatter, LongitudeFormatter -from matplotlib.colors import hsv_to_rgb - -from e3sm_diags.derivations.default_regions import regions_specs -from e3sm_diags.driver.utils.general import get_output_dir -from e3sm_diags.logger import custom_logger - -logger = custom_logger(__name__) - -matplotlib.use("Agg") # noqa: E402 -import matplotlib.pyplot as plt # isort:skip # noqa: E402 - - -plotTitle = {"fontsize": 11.5} -plotSideTitle = {"fontsize": 9.5} - -# Position and sizes of subplot axes in page coordinates (0 to 1) -panel = [ - (0.1691, 0.55, 0.6465, 0.2758), - (0.1691, 0.15, 0.6465, 0.2758), -] -# Border padding relative to subplot axes for saving individual panels -# (left, bottom, right, top) in page coordinates -border = (-0.06, -0.03, 0.13, 0.03) - - -def add_cyclic(var): - lon = var.getLongitude() - return var(longitude=(lon[0], lon[0] + 360.0, "coe")) - - -def get_ax_size(fig, ax): - bbox = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted()) - width, height = bbox.width, bbox.height - width *= fig.dpi - height *= fig.dpi - return width, height - - -def determine_tick_step(degrees_covered): - if degrees_covered >= 270: - return 60 - if degrees_covered >= 180: - return 30 - if degrees_covered >= 90: - return 25 - if degrees_covered >= 60: - return 20 - elif degrees_covered >= 30: - return 10 - elif degrees_covered >= 20: - return 5 - else: - return 1 - - -def plot_panel(n, fig, proj, var, amp, amp_ref, title, parameter): - normalize_test_amp = parameter.normalize_test_amp - specified_max_amp = parameter.normalize_amp_int - - lat = var.getLatitude() - var = ma.squeeze(var.asma()) - max_amp = round(amp.max()) - max_amp_ref = round(amp_ref.max()) - amp = ma.squeeze(amp.asma()) - amp_ref = ma.squeeze(amp_ref.asma()) - - if normalize_test_amp: - img = np.dstack( - ((var / 24 - 0.5) % 1, (amp / max_amp_ref) ** 0.5, np.ones_like(amp)) - ) - max_amp = max_amp_ref - logger.info( - f"Scale test diurnal cycle amplitude to max of reference ({max_amp_ref}) mm/day" - ) - else: - if specified_max_amp != 0: - max_amp = specified_max_amp - - img = np.dstack( - ((var / 24 - 0.5) % 1, (amp / max_amp) ** 0.5, np.ones_like(amp)) - ) - logger.info(f"Scale test diurnal cycle amplitude to specified {max_amp} mm/day") - # Note: hsv_to_rgb would clipping input data to the valid range for imshow with RGB data ([0..1] - img = hsv_to_rgb(img) - - # imshow plot - ax = fig.add_axes(panel[n], projection=proj) - - region_str = parameter.regions[0] - region = regions_specs[region_str] - global_domain = True - full_lon = True - if "domain" in region.keys(): # type: ignore - # Get domain to plot - domain = region["domain"] # type: ignore - global_domain = False - else: - # Assume global domain - domain = cdutil.region.domain(latitude=(-90.0, 90, "ccb")) - kargs = domain.components()[0].kargs - # lon_west, lon_east, lat_south, lat_north = (0, 360, -90, 90) - lon_west, lon_east, lat_south, lat_north = (-180, 180, -90, 90) - if "longitude" in kargs: - full_lon = False - lon_west, lon_east, _ = kargs["longitude"] - # Note cartopy Problem with gridlines across the dateline:https://github.com/SciTools/cartopy/issues/821. Region cross dateline is not supported yet. - if lon_west > 180 and lon_east > 180: - lon_west = lon_west - 360 - lon_east = lon_east - 360 - - if "latitude" in kargs: - lat_south, lat_north, _ = kargs["latitude"] - lon_covered = lon_east - lon_west - lon_step = determine_tick_step(lon_covered) - xticks = np.arange(lon_west, lon_east, lon_step) - # Subtract 0.50 to get 0 W to show up on the right side of the plot. - # If less than 0.50 is subtracted, then 0 W will overlap 0 E on the left side of the plot. - # If a number is added, then the value won't show up at all. - if global_domain or full_lon: - xticks = [0, 60, 120, 180, 240, 300, 359.99] # type: ignore - else: - xticks = np.append(xticks, lon_east) - proj = ccrs.PlateCarree() - - lat_covered = lat_north - lat_south - lat_step = determine_tick_step(lat_covered) - yticks = np.arange(lat_south, lat_north, lat_step) - yticks = np.append(yticks, lat_north) - - ax.set_extent([lon_west, lon_east, lat_south, lat_north]) # , crs=proj) - - # Full world would be aspect 360/(2*180) = 1 - # ax.set_aspect((lon_east - lon_west)/(2*(lat_north - lat_south))) - ax.coastlines(lw=0.3) - if title[0] is not None: - ax.set_title(title[0], loc="left", fontdict=plotSideTitle) - if title[1] is not None: - ax.set_title(title[1], fontdict=plotTitle) - ax.set_xticks(xticks, crs=ccrs.PlateCarree()) - # ax.set_xticks([0, 60, 120, 180, 240, 300, 359.99], crs=ccrs.PlateCarree()) - ax.set_yticks(yticks, crs=ccrs.PlateCarree()) - lon_formatter = LongitudeFormatter(zero_direction_label=True, number_format=".0f") - lat_formatter = LatitudeFormatter() - ax.xaxis.set_major_formatter(lon_formatter) - ax.yaxis.set_major_formatter(lat_formatter) - ax.tick_params(labelsize=8.0, direction="out", width=1) - ax.xaxis.set_ticks_position("bottom") - ax.yaxis.set_ticks_position("left") - # set a margin around the data - ax.set_xmargin(0.05) - ax.set_ymargin(0.10) - - ax.set_ylim([yticks[0], yticks[-1]]) - - # add the image. Because this image was a tif, the "origin" of the image is in the - # upper left corner - img_extent = [lon_west, lon_east, lat_south, lat_north] - - # When the requested region is inconsistent with what the data covered (`global` is secified but TRMM only has 50S-5N), set an arbitrary threhold. - if global_domain and lat_covered - abs(lat[0] - lat[-1]) > 10: - img_extent = [lon_west, lon_east, lat[0], lat[-1]] - # ax.imshow(img, origin='lower', extent=img_extent, transform=ccrs.PlateCarree()) - ax.imshow(img, origin="lower", extent=img_extent, transform=proj) - if region_str == "CONUS": - ax.coastlines(resolution="50m", color="black", linewidth=0.3) - state_borders = cfeature.NaturalEarthFeature( - category="cultural", - name="admin_1_states_provinces_lakes", - scale="50m", - facecolor="none", - ) - ax.add_feature(state_borders, edgecolor="black") - - # Color bar - bar_ax = fig.add_axes( - (panel[n][0] + 0.67, panel[n][1] + 0.2, 0.07, 0.07), polar=True - ) - theta, R = np.meshgrid(np.linspace(0, 2 * np.pi, 24), np.linspace(0, 1, 8)) - H, S = np.meshgrid(np.linspace(0, 1, 24), np.linspace(0, 1, 8)) - image = np.dstack(((H - 0.5) % 1, S**0.5, np.ones_like(S))) - image = hsv_to_rgb(image) - # bar_ax.set_theta_zero_location('N') - bar_ax.set_theta_direction(-1) - bar_ax.set_theta_offset(np.pi / 2) - bar_ax.set_xticklabels(["0h", "3h", "6h", "9h", "12h", "15h", "18h", "21h"]) - bar_ax.set_yticklabels(["", "", f"{int(max_amp)}"]) - bar_ax.set_rlabel_position(350) - bar_ax.get_yticklabels()[-2].set_weight("bold") - # We change the fontsize of minor ticks label - bar_ax.tick_params(axis="both", labelsize=7, pad=0, length=0) - bar_ax.text( - 0.2, - -0.3, - "Local Time", - transform=bar_ax.transAxes, - fontsize=7, - verticalalignment="center", - ) - bar_ax.text( - -0.1, - -0.9, - "Max DC amp {:.2f}{}".format(amp.max(), "mm/d"), - transform=bar_ax.transAxes, - fontsize=7, - fontweight="bold", - verticalalignment="center", - ) - bar_ax.text( - -0.1, - -0.5, - "DC phase (Hue)", - transform=bar_ax.transAxes, - fontsize=7, - verticalalignment="center", - ) - bar_ax.text( - -0.1, - -0.7, - "DC amplitude (Saturation)", - transform=bar_ax.transAxes, - fontsize=7, - verticalalignment="center", - ) - color = image.reshape((image.shape[0] * image.shape[1], image.shape[2])) - pc = bar_ax.pcolormesh(theta, R, np.zeros_like(R), color=color, shading="auto") - pc.set_array(None) - - -def plot(test_tmax, test_amp, ref_tmax, ref_amp, parameter): - if parameter.backend not in ["cartopy", "mpl", "matplotlib"]: - return - - # Create figure, projection - fig = plt.figure(figsize=[8.5, 8.5], dpi=parameter.dpi) - proj = ccrs.PlateCarree(central_longitude=180) - - # First panel - plot_panel( - 0, - fig, - proj, - test_tmax, - test_amp, - ref_amp, - (parameter.test_name_yrs, parameter.test_title), - parameter, - ) - - # Second panel - plot_panel( - 1, - fig, - proj, - ref_tmax, - ref_amp, - ref_amp, - (parameter.ref_name_yrs, parameter.reference_title), - parameter, - ) - - # Figure title - fig.suptitle(parameter.main_title, x=0.5, y=0.9, fontsize=14) - - # Prepare to save figure - # get_output_dir => {parameter.results_dir}/{set_name}/{parameter.case_id} - # => {parameter.results_dir}/enso_diags/{parameter.case_id} - output_dir = get_output_dir(parameter.current_set, parameter) - if parameter.print_statements: - logger.info("Output dir: {}".format(output_dir)) - # get_output_dir => {parameter.orig_results_dir}/{set_name}/{parameter.case_id} - # => {parameter.orig_results_dir}/enso_diags/{parameter.case_id} - original_output_dir = get_output_dir(parameter.current_set, parameter) - if parameter.print_statements: - logger.info("Original output dir: {}".format(original_output_dir)) - # parameter.output_file is defined in e3sm_diags/driver/enso_diags_driver.py - # {parameter.results_dir}/enso_diags/{parameter.case_id}/{parameter.output_file} - file_path = os.path.join(output_dir, parameter.output_file) - # {parameter.orig_results_dir}/enso_diags/{parameter.case_id}/{parameter.output_file} - original_file_path = os.path.join(original_output_dir, parameter.output_file) - - # Save figure - for f in parameter.output_format: - f = f.lower().split(".")[-1] - plot_suffix = "." + f - plot_file_path = file_path + plot_suffix - plt.savefig(plot_file_path) - # Get the filename that the user has passed in and display that. - original_plot_file_path = original_file_path + plot_suffix - logger.info(f"Plot saved in: {original_plot_file_path}") - - # Save individual subplots - for f in parameter.output_format_subplot: - page = fig.get_size_inches() - i = 0 - for p in panel: - # Extent of subplot - subpage = np.array(p).reshape(2, 2) - subpage[1, :] = subpage[0, :] + subpage[1, :] - subpage = subpage + np.array(border).reshape(2, 2) - subpage = list(((subpage) * page).flatten()) # type: ignore - extent = matplotlib.transforms.Bbox.from_extents(*subpage) - # Save subplot - subplot_suffix = ".%i." % (i) + f - subplot_file_path = file_path + subplot_suffix - plt.savefig(subplot_file_path, bbox_inches=extent) - # Get the filename that the user has passed in and display that. - original_subplot_file_path = original_file_path + subplot_suffix - logger.info(f"Sub-plot saved in: {original_subplot_file_path}") - i += 1 - - plt.close() diff --git a/e3sm_diags/plot/diurnal_cycle_plot.py b/e3sm_diags/plot/diurnal_cycle_plot.py new file mode 100644 index 000000000..9a0625556 --- /dev/null +++ b/e3sm_diags/plot/diurnal_cycle_plot.py @@ -0,0 +1,309 @@ +from typing import Tuple + +import cartopy.crs as ccrs +import cartopy.feature as cfeature +import matplotlib +import numpy as np +import xarray as xr +import xcdat as xc +from matplotlib.colors import hsv_to_rgb + +from e3sm_diags.derivations.default_regions_xr import REGION_SPECS +from e3sm_diags.logger import custom_logger +from e3sm_diags.parameter.diurnal_cycle_parameter import DiurnalCycleParameter +from e3sm_diags.plot.utils import ( + _configure_titles, + _configure_x_and_y_axes, + _get_x_ticks, + _get_y_ticks, + _save_plot, +) + +logger = custom_logger(__name__) + +matplotlib.use("Agg") # noqa: E402 +import matplotlib.pyplot as plt # isort:skip # noqa: E402 + + +# Position and sizes of subplot axes in page coordinates (0 to 1) +PANEL_CFG = [ + (0.1691, 0.55, 0.6465, 0.2758), + (0.1691, 0.15, 0.6465, 0.2758), +] + + +def plot( + test_maxtime: xr.DataArray, + test_amplitude: xr.DataArray, + ref_maxtime: xr.DataArray, + ref_amplitude: xr.DataArray, + parameter: DiurnalCycleParameter, +): + fig = plt.figure(figsize=(8.5, 8.5), dpi=parameter.dpi) + fig.suptitle(parameter.main_title, x=0.5, y=0.9, fontsize=14) + + _add_colormap( + 0, + test_maxtime, + test_amplitude, + ref_amplitude, + fig, + parameter, + (parameter.test_name_yrs, parameter.test_title, None), + ) + + _add_colormap( + 1, + ref_maxtime, + ref_amplitude, + ref_amplitude, + fig, + parameter, + (parameter.ref_name_yrs, parameter.reference_title, None), + ) + + _save_plot(fig, parameter, PANEL_CFG) + + plt.close() + + +def _add_colormap( + subplot_num: int, + test_maxtime: xr.DataArray, + test_amplitude: xr.DataArray, + ref_maxtime: xr.DataArray, + fig: plt.Figure, + parameter: DiurnalCycleParameter, + title: Tuple[str, str, None], +): + """Adds a colormap containing the test max time, test amplitude, and ref amplitude. + + Parameters + ---------- + subplot_num : int + The subplot number + test_maxtime : xr.DataArray + The test max time. + test_amplitude : xr.DataArray + The test amplitude. + ref_amplitude : xr.DataArray + The ref amplitude. + fig : plt.Figure + The figure object to add the subplot to. + parameter : DiurnalCycleParameter + The parameter object containing plot configurations. + title : Tuple[str, str, None] + A tuple of strings to fomr the title of the color in the format + (test_name_yrs, reference_title). None is the third value because + the child function expects a tuple of three optional strings. + """ + normalize_test_amp = parameter.normalize_test_amp + specified_max_amp = parameter.normalize_amp_int + + lat = xc.get_dim_coords(test_maxtime, axis="Y") + test_maxtime = test_maxtime.squeeze() + max_amp = round(test_amplitude.max().item()) + max_amp_ref = round(ref_maxtime.max().item()) + test_amplitude = test_amplitude.squeeze() + ref_maxtime = ref_maxtime.squeeze() + + if normalize_test_amp: + img = np.dstack( + ( + (test_maxtime / 24 - 0.5) % 1, + (test_amplitude / max_amp_ref) ** 0.5, + np.ones_like(test_amplitude), + ) + ) + max_amp = max_amp_ref + logger.info( + f"Scale test diurnal cycle amplitude to max of reference ({max_amp_ref}) mm/day" + ) + else: + if specified_max_amp != 0: + max_amp = specified_max_amp + + img = np.dstack( + ( + (test_maxtime / 24 - 0.5) % 1, + (test_amplitude / max_amp) ** 0.5, + np.ones_like(test_amplitude), + ) + ) + logger.info(f"Scale test diurnal cycle amplitude to specified {max_amp} mm/day") + + # NOTE: hsv_to_rgb would clipping input data to the valid range for imshow + # with RGB data ([0..1] + img = hsv_to_rgb(img) + + # Get region info and X and Y plot ticks. + # -------------------------------------------------------------------------- + region_key = parameter.regions[0] + region_specs = REGION_SPECS[region_key] + + # Get the region's domain slices for latitude and longitude if set, or + # use the default value. If both are not set, then the region type is + # considered "global". + lat_slice = region_specs.get("lat", (-90, 90)) # type: ignore + lon_slice = region_specs.get("lon", (-180, 180)) # type: ignore + + # Boolean flags for configuring plots. + is_global_domain = lat_slice == (-90, 90) and lon_slice == (-180, 180) + is_lon_full = lon_slice == (-180, 180) + + # Determine X and Y ticks using longitude and latitude domains respectively. + lon_west, lon_east = lon_slice + x_ticks = _get_x_ticks( + lon_west, + lon_east, + is_global_domain, + is_lon_full, + axis_orientation=360, + tick_step_func=_determine_tick_step, + ) + + lat_south, lat_north = lat_slice + y_ticks = _get_y_ticks(lat_south, lat_north, tick_step_func=_determine_tick_step) + + # Get the figure Axes object using the projection above. + # -------------------------------------------------------------------------- + ax = fig.add_axes( + PANEL_CFG[subplot_num], projection=ccrs.PlateCarree(central_longitude=180) + ) + + # Configure the aspect ratio and coast lines. + # -------------------------------------------------------------------------- + # Full world would be aspect 360/(2*180) = 1 + ax.set_extent([lon_west, lon_east, lat_south, lat_north]) + ax.coastlines(lw=0.3) + + # Configure the titles and x and y axes. + # -------------------------------------------------------------------------- + _configure_titles(ax, title) + + _configure_x_and_y_axes( + ax, x_ticks, y_ticks, ccrs.PlateCarree(), parameter.current_set + ) + + ax.set_xmargin(0.05) + ax.set_ymargin(0.10) + ax.set_ylim([y_ticks[0], y_ticks[-1]]) + + # # Add the image. Because this image was a tif, the "origin" of the image + # is in the upper left corner + # -------------------------------------------------------------------------- + img_extent = [lon_west, lon_east, lat_south, lat_north] + + # Get the cartopy projection based on region info. + # -------------------------------------------------------------------------- + # When the requested region is inconsistent with what the data covered + # (`global`) is secified but TRMM only has 50S-5N), set an arbitrary + # threhold. + lat_covered = lat_north - lat_south + if is_global_domain and lat_covered - abs(lat[0] - lat[-1]) > 10: + img_extent = [lon_west, lon_east, lat[0], lat[-1]] + + imshow_projection = ccrs.PlateCarree() + if is_global_domain or is_lon_full: + imshow_projection = ccrs.PlateCarree(central_longitude=180) + + ax.imshow(img, origin="lower", extent=img_extent, transform=imshow_projection) + + if region_key == "CONUS": + ax.coastlines(resolution="50m", color="black", linewidth=0.3) + state_borders = cfeature.NaturalEarthFeature( + category="cultural", + name="admin_1_states_provinces_lakes", + scale="50m", + facecolor="none", + ) + ax.add_feature(state_borders, edgecolor="black") + + # Configure the colorbar + # -------------------------------------------------------------------------- + bar_ax = fig.add_axes( + (PANEL_CFG[subplot_num][0] + 0.67, PANEL_CFG[subplot_num][1] + 0.2, 0.07, 0.07), + polar=True, + ) + + H, S = np.meshgrid(np.linspace(0, 1, 24), np.linspace(0, 1, 8)) + image = np.dstack(((H - 0.5) % 1, S**0.5, np.ones_like(S))) + image = hsv_to_rgb(image) + + bar_ax.set_theta_direction(-1) + bar_ax.set_theta_offset(np.pi / 2) + bar_ax.set_rlabel_position(350) + + bar_ax.set_xticklabels(["0h", "3h", "6h", "9h", "12h", "15h", "18h", "21h"]) + bar_ax.set_yticklabels(["", "", f"{int(max_amp)}"]) + bar_ax.get_yticklabels()[-2].set_weight("bold") + + # Update the fontsize of minor ticks label. + bar_ax.tick_params(axis="both", labelsize=7, pad=0, length=0) + bar_ax.text( + 0.2, + -0.3, + "Local Time", + transform=bar_ax.transAxes, + fontsize=7, + verticalalignment="center", + ) + bar_ax.text( + -0.1, + -0.9, + "Max DC amp {:.2f}{}".format(test_amplitude.max(), "mm/d"), + transform=bar_ax.transAxes, + fontsize=7, + fontweight="bold", + verticalalignment="center", + ) + bar_ax.text( + -0.1, + -0.5, + "DC phase (Hue)", + transform=bar_ax.transAxes, + fontsize=7, + verticalalignment="center", + ) + bar_ax.text( + -0.1, + -0.7, + "DC amplitude (Saturation)", + transform=bar_ax.transAxes, + fontsize=7, + verticalalignment="center", + ) + + theta, R = np.meshgrid(np.linspace(0, 2 * np.pi, 24), np.linspace(0, 1, 8)) + color = image.reshape((image.shape[0] * image.shape[1], image.shape[2])) + pc = bar_ax.pcolormesh(theta, R, np.zeros_like(R), color=color, shading="auto") + pc.set_array(None) + + +def _determine_tick_step(degrees_covered: float) -> int: + """Determine the number of tick steps based on the degrees covered by the axis. + + Parameters + ---------- + degrees_covered : float + The degrees covered by the axis. + + Returns + ------- + int + The number of tick steps. + """ + if degrees_covered >= 270: + return 60 + if degrees_covered >= 180: + return 30 + if degrees_covered >= 90: + return 25 + if degrees_covered >= 60: + return 20 + elif degrees_covered >= 30: + return 10 + elif degrees_covered >= 20: + return 5 + else: + return 1 diff --git a/e3sm_diags/plot/utils.py b/e3sm_diags/plot/utils.py index ad308dbe5..5ffa65486 100644 --- a/e3sm_diags/plot/utils.py +++ b/e3sm_diags/plot/utils.py @@ -1,7 +1,7 @@ from __future__ import annotations import os -from typing import List, Tuple +from typing import Callable, List, Literal, Tuple import cartopy.crs as ccrs import matplotlib @@ -246,8 +246,38 @@ def _add_contour_plot( return c_plot +def _determine_tick_step(degrees_covered: float) -> int: + """Determine the number of tick steps based on the degrees covered by the axis. + + Parameters + ---------- + degrees_covered : float + The degrees covered by the axis. + + Returns + ------- + int + The number of tick steps. + """ + if degrees_covered > 180: + return 60 + if degrees_covered > 60: + return 30 + elif degrees_covered > 30: + return 10 + elif degrees_covered > 20: + return 5 + else: + return 1 + + def _get_x_ticks( - lon_west: float, lon_east: float, is_global_domain: bool, is_lon_full: bool + lon_west: float, + lon_east: float, + is_global_domain: bool, + is_lon_full: bool, + axis_orientation: Literal[180, 360] = 180, + tick_step_func: Callable = _determine_tick_step, ) -> np.ndarray: """Get the X axis ticks based on the longitude domain slice. @@ -261,6 +291,11 @@ def _get_x_ticks( If the domain type is "global". is_lon_full : bool True if the longitude domain is (0, 360). + axis_orientation : Literal[180, 360] + The longitude axis orientation, by default 180. + tick_step_func : Callable + A function to determine the tick step, which might vary between sets, + by default `_determine_tick_step`. Returns ------- @@ -276,7 +311,7 @@ def _get_x_ticks( lon_east = lon_east - 360 lon_covered = lon_east - lon_west - lon_step = _determine_tick_step(lon_covered) + lon_step = tick_step_func(lon_covered) x_ticks = np.arange(lon_west, lon_east, lon_step) @@ -285,14 +320,21 @@ def _get_x_ticks( # If less than 0.50 is subtracted, then 0 W will overlap 0 E on the # left side of the plot. If a number is added, then the value won't # show up at all. - x_ticks = np.append(x_ticks, lon_east - 0.50) + if axis_orientation == 360: + x_ticks = np.array([0, 60, 120, 180, 240, 300, 359.99], dtype=float) + else: + x_ticks = np.append(x_ticks, lon_east - 0.50) else: x_ticks = np.append(x_ticks, lon_east) return x_ticks -def _get_y_ticks(lat_south: float, lat_north: float) -> np.ndarray: +def _get_y_ticks( + lat_south: float, + lat_north: float, + tick_step_func: Callable = _determine_tick_step, +) -> np.ndarray: """Get Y axis ticks. Parameters @@ -301,6 +343,9 @@ def _get_y_ticks(lat_south: float, lat_north: float) -> np.ndarray: The south point (e.g., -180). lat_north : float The north point (e.g., 180). + tick_step_func : Callable + A function to determine the tick step, which might vary between sets, + by default `_determine_tick_step`. Returns ------- @@ -309,41 +354,16 @@ def _get_y_ticks(lat_south: float, lat_north: float) -> np.ndarray: """ lat_covered = lat_north - lat_south - lat_step = _determine_tick_step(lat_covered) + lat_step = tick_step_func(lat_covered) y_ticks = np.arange(lat_south, lat_north, lat_step) y_ticks = np.append(y_ticks, lat_north) return y_ticks -def _determine_tick_step(degrees_covered: float) -> int: - """Determine the number of tick steps based on the degrees covered by the axis. - - Parameters - ---------- - degrees_covered : float - The degrees covered by the axis. - - Returns - ------- - int - The number of tick steps. - """ - if degrees_covered > 180: - return 60 - if degrees_covered > 60: - return 30 - elif degrees_covered > 30: - return 10 - elif degrees_covered > 20: - return 5 - else: - return 1 - - def _configure_titles( ax: matplotlib.axes.Axes, - title: Tuple[str | None, str, str], + title: Tuple[str | None, str | None, str | None], main_fontsize: float = MAIN_TITLE_FONTSIZE, secondary_fontsize: float = SECONDARY_TITLE_FONTSIZE, ): @@ -353,7 +373,7 @@ def _configure_titles( ---------- ax : matplotlib.axes.Axes The figure axes object. - title : Tuple[str | None, str, str] + title : Tuple[str | None, str | None, str | None] A tuple of strings to form the title of the colormap, in the format ( years, title, units). main_fontsize : float