{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "06f3f346-a06c-4455-ace7-4bb8e38c6ee0",
   "metadata": {},
   "source": [
    "# RECMORISATION "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e90fa7b-f621-45a2-951d-9f2cb3850486",
   "metadata": {},
   "source": [
    "Conda environment created with cmor v3.13 a recent version of iris and ipykernel to allow interface with Jupyterhub"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "d3ee49f8-e8c3-4de1-b679-5b3608b6f957",
   "metadata": {},
   "outputs": [],
   "source": [
    "import cmor  # used for writing files\n",
    "import iris  # used for reading files -- netCDF4 or xarray could be used here based on preference\n",
    "import json\n",
    "import os"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1c4ca8b1-edd3-4738-a886-6bef149b3010",
   "metadata": {},
   "source": [
    "### CMOR input json"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "263cc133-67d9-42ec-9a39-6e6e6deeb923",
   "metadata": {},
   "outputs": [],
   "source": [
    "DATASET_INFO = {\n",
    "    \"_AXIS_ENTRY_FILE\": \"tables/CMIP7_coordinate.json\",\n",
    "    \"_FORMULA_VAR_FILE\": \"tables/CMIP7_formula_terms.json\",\n",
    "    \"_cmip7_option\": 1,\n",
    "    \"_controlled_vocabulary_file\": \"test/CMIP7-CV_for-cmor.json\",\n",
    "    \"activity_id\": \"CMIP\",\n",
    "    \"branch_method\": \"standard\",\n",
    "    \"branch_time_in_child\": 30.0,\n",
    "    \"branch_time_in_parent\": 10800.0,\n",
    "    \"calendar\": \"360_day\",\n",
    "    \"cv_version\": \"7.0.0.0\",\n",
    "    \"drs_specs\": \"MIP-DRS7\",\n",
    "    \"experiment_id\": \"historical\",\n",
    "    \"forcing_index\": \"f3\",\n",
    "    \"grid\": \"N96\",\n",
    "    \"grid_label\": \"gn\",\n",
    "    \"initialization_index\": \"i1\",\n",
    "    \"institution_id\": \"PCMDI\",\n",
    "    \"license_id\": \"CC BY 4.0\",\n",
    "    \"nominal_resolution\": \"250 km\",\n",
    "    \"outpath\": \".\",\n",
    "    \"parent_mip_era\": \"CMIP7\",\n",
    "    \"parent_time_units\": \"days since 1850-01-01\",\n",
    "    \"parent_activity_id\": \"CMIP\",\n",
    "    \"parent_source_id\": \"PCMDI-test-1-0\",\n",
    "    \"parent_experiment_id\": \"piControl\",\n",
    "    \"parent_variant_label\": \"r1i1p1f3\",\n",
    "    \"physics_index\": \"p1\",\n",
    "    \"realization_index\": \"r1\",\n",
    "    \"source_id\": \"PCMDI-test-1-0\",\n",
    "    \"source_type\": \"AOGCM CHEM BGC\",\n",
    "    \"tracking_prefix\": \"hdl:21.14100\",\n",
    "    \"host_collection\": \"CMIP7\",\n",
    "    \"frequency\": \"mon\",\n",
    "    \"region\": \"GLB\",\n",
    "    \"archive_id\": \"WCRP\",\n",
    "    \"mip_era\": \"CMIP7\",\n",
    "}\n",
    "\n",
    "with open('input.json', 'w') as fh:\n",
    "    json.dump(DATASET_INFO, fh, indent=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "02c0b14c-3e40-419a-b59c-fe78b709208c",
   "metadata": {},
   "source": [
    "### Get hold of data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "65f4d241-8b3d-4165-b013-bf64ad59d0b7",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/users/msmizielinski/.conda/envs/CMOR-3.13/lib/python3.13/site-packages/pyproj/network.py:59: UserWarning: pyproj unable to set PROJ database path.\n",
      "  _set_context_ca_bundle_path(ca_bundle_path)\n",
      "/home/users/msmizielinski/.conda/envs/CMOR-3.13/lib/python3.13/site-packages/iris/fileformats/cf.py:934: IrisCfMissingVarWarning: Missing CF-netCDF measure variable 'areacella', referenced by netCDF variable 'tas'\n",
      "  warnings.warn(\n",
      "/home/users/msmizielinski/.conda/envs/CMOR-3.13/lib/python3.13/site-packages/iris/fileformats/cf.py:934: IrisCfMissingVarWarning: Missing CF-netCDF measure variable 'areacella', referenced by netCDF variable 'pr'\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "LOCAL_CMIP6_ROOT = '/badc/cmip6/data/'  # will be different in other places\n",
    "\n",
    "\n",
    "# Load all existing monthly tas data as a single iris cube;\n",
    "\n",
    "cubelist = iris.load(LOCAL_CMIP6_ROOT + 'CMIP6/CMIP/MOHC/UKESM1-0-LL/1pctCO2/r1i1p1f2/Amon/tas/gn/v20190406/tas*.nc')\n",
    "\n",
    "for i in cubelist:\n",
    "    i.attributes = {}\n",
    "\n",
    "tas_cube = cubelist.concatenate_cube()\n",
    "\n",
    "# load all existing monthly pr data as a single iris cube\n",
    "\n",
    "cubelist = iris.load(LOCAL_CMIP6_ROOT + 'CMIP6/CMIP/MOHC/UKESM1-0-LL/1pctCO2/r1i1p1f2/Amon/pr/gn/v20190406/pr*.nc')\n",
    "\n",
    "for i in cubelist:\n",
    "    i.attributes = {}\n",
    "\n",
    "pr_cube = cubelist.concatenate_cube()\n",
    "\n",
    "# warnings related to missing CF netcdf or pyproj can be ignored."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dde9741b-42ee-420e-ab4d-6ed0df901244",
   "metadata": {},
   "source": [
    "### Setup CMOR"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d758a9d7-59f5-49ef-96bb-94d9ab0a3e2b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cmor.setup(inpath=\"tables\", netcdf_file_action=cmor.CMOR_REPLACE)\n",
    "\n",
    "cmor.dataset_json('input.json')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "35dcd517-505e-4352-931a-982c03850f3f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "realm = \"atmos\"\n",
    "cmor.load_table(f'CMIP7_{realm}.json')\n",
    "\n",
    "# warnings in this can be ignored -- the metadata in the tables is not perfectly set up"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7db14cd6-b720-4ea9-899c-94aec56e0ad7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# retrieve cell measures info\n",
    "with open('tables/CMIP7_cell_measures.json') as fh:\n",
    "    cell_measures = json.load(fh)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "19bb6786-91b6-45c0-9593-da44f598df3d",
   "metadata": {},
   "source": [
    "### Write tas (50 record chunks)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f9a49cb7-ad8a-4fbe-9788-f1629c23d2b6",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "slice(0, 50, None)\n",
      "slice(50, 100, None)\n",
      "slice(100, 150, None)\n",
      "slice(150, 200, None)\n",
      "slice(200, 250, None)\n",
      "slice(250, 300, None)\n",
      "slice(300, 350, None)\n",
      "slice(350, 400, None)\n",
      "slice(400, 450, None)\n",
      "slice(450, 500, None)\n",
      "slice(500, 550, None)\n",
      "slice(550, 600, None)\n",
      "slice(600, 650, None)\n",
      "slice(650, 700, None)\n",
      "slice(700, 750, None)\n",
      "slice(750, 800, None)\n",
      "slice(800, 850, None)\n",
      "slice(850, 900, None)\n",
      "slice(900, 950, None)\n",
      "slice(950, 1000, None)\n",
      "slice(1000, 1050, None)\n",
      "slice(1050, 1100, None)\n",
      "slice(1100, 1150, None)\n",
      "slice(1150, 1200, None)\n",
      "slice(1200, 1250, None)\n",
      "slice(1250, 1300, None)\n",
      "slice(1300, 1350, None)\n",
      "slice(1350, 1400, None)\n",
      "slice(1400, 1450, None)\n",
      "slice(1450, 1500, None)\n",
      "slice(1500, 1550, None)\n",
      "slice(1550, 1600, None)\n",
      "slice(1600, 1650, None)\n",
      "slice(1650, 1700, None)\n",
      "slice(1700, 1750, None)\n",
      "slice(1750, 1800, None)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'./MIP-DRS7//CMIP7//CMIP//PCMDI//PCMDI-test-1-0//historical//r1i1p1f3//GLB//mon//tas//tavg-h2m-hxy-u//gn//v20251016/tas_tavg-h2m-hxy-u_mon_GLB_gn_PCMDI-test-1-0_historical_r1i1p1f3_185001-199912.nc'"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# construct latitude and longitude coords\n",
    "cmorlat = cmor.axis(\"latitude\",\n",
    "                    coord_vals=tas_cube.coord('latitude').points,\n",
    "                    cell_bounds=tas_cube.coord('latitude').bounds,\n",
    "                    units=\"degrees_north\")\n",
    "cmorlon = cmor.axis(\"longitude\",\n",
    "                    coord_vals=tas_cube.coord('longitude').points,\n",
    "                    cell_bounds=tas_cube.coord('longitude').bounds,\n",
    "                    units=\"degrees_east\")\n",
    "# construct time coord in a way that we can update with points and bounds later\n",
    "cmortime = cmor.axis(\"time\", units=\"days since 1850-01-01\")\n",
    "# define CMOR variable object\n",
    "axes = [cmortime, cmorlat, cmorlon]\n",
    "\n",
    "variable = \"tas_tavg-h2m-hxy-u\"\n",
    "cmortas = cmor.variable(variable, \"K\", axes)\n",
    "\n",
    "# manually apply cell measures\n",
    "region = DATASET_INFO['region']\n",
    "frequency = DATASET_INFO['frequency']\n",
    "cell_measures_key = \".\".join([realm] + variable.split(\"_\") + [frequency, region])\n",
    "\n",
    "# Check that cell_measures are valid ( option flags need to be manually replaced )\n",
    "variable_cell_measures = cell_measures[cell_measures_key]\n",
    "if variable_cell_measures in [\"::OPT\", \"::MODEL\"]:\n",
    "    raise RuntimeError(f\"found cell_measures '{variable_cell_measures}' which CMOR will not allow\")\n",
    "    \n",
    "cmor.set_variable_attribute(cmortas, \"cell_measures\", \"c\", variable_cell_measures)\n",
    "# slice up data into N time record chunks and push through CMOR.write\n",
    "N = 50\n",
    "for i in range(0, 1800, N):\n",
    "    s = slice(i, i+N)\n",
    "    print(s)\n",
    "    cube_slice = tas_cube[s]\n",
    "    cmor.write(\n",
    "        cmortas,\n",
    "        cube_slice.data, \n",
    "        time_vals=cube_slice.coord('time').points, \n",
    "        time_bnds=cube_slice.coord('time').bounds)\n",
    "\n",
    "# close the file (sorts the full naming)\n",
    "cmor.close(cmortas, file_name=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "c8cc4915-30cb-4580-b09f-ea990004e157",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "netcdf tas_tavg-h2m-hxy-u_mon_GLB_gn_PCMDI-test-1-0_historical_r1i1p1f3_185001-199912 {\n",
      "dimensions:\n",
      "\ttime = UNLIMITED ; // (1800 currently)\n",
      "\tlat = 144 ;\n",
      "\tlon = 192 ;\n",
      "\tbnds = 2 ;\n",
      "variables:\n",
      "\tdouble time(time) ;\n",
      "\t\ttime:bounds = \"time_bnds\" ;\n",
      "\t\ttime:units = \"days since 1850-01-01\" ;\n",
      "\t\ttime:calendar = \"360_day\" ;\n",
      "\t\ttime:axis = \"T\" ;\n",
      "\t\ttime:long_name = \"Time Intervals\" ;\n",
      "\t\ttime:standard_name = \"time\" ;\n",
      "\tdouble time_bnds(time, bnds) ;\n",
      "\tdouble lat(lat) ;\n",
      "\t\tlat:bounds = \"lat_bnds\" ;\n",
      "\t\tlat:units = \"degrees_north\" ;\n",
      "\t\tlat:axis = \"Y\" ;\n",
      "\t\tlat:long_name = \"Latitude\" ;\n",
      "\t\tlat:standard_name = \"latitude\" ;\n",
      "\tdouble lat_bnds(lat, bnds) ;\n",
      "\tdouble lon(lon) ;\n",
      "\t\tlon:bounds = \"lon_bnds\" ;\n",
      "\t\tlon:units = \"degrees_east\" ;\n",
      "\t\tlon:axis = \"X\" ;\n",
      "\t\tlon:long_name = \"Longitude\" ;\n",
      "\t\tlon:standard_name = \"longitude\" ;\n",
      "\tdouble lon_bnds(lon, bnds) ;\n",
      "\tdouble height ;\n",
      "\t\theight:units = \"m\" ;\n",
      "\t\theight:axis = \"Z\" ;\n",
      "\t\theight:positive = \"up\" ;\n",
      "\t\theight:long_name = \"height\" ;\n",
      "\t\theight:standard_name = \"height\" ;\n",
      "\tfloat tas(time, lat, lon) ;\n",
      "\t\ttas:standard_name = \"air_temperature\" ;\n",
      "\t\ttas:long_name = \"Near-Surface Air Temperature\" ;\n",
      "\t\ttas:units = \"K\" ;\n",
      "\t\ttas:cell_methods = \"area: time: mean\" ;\n",
      "\t\ttas:history = \"2025-10-16T14:36:16Z altered by CMOR: Treated scalar dimension: \\'height\\'.\" ;\n",
      "\t\ttas:coordinates = \"height\" ;\n",
      "\t\ttas:missing_value = 1.e+20f ;\n",
      "\t\ttas:_FillValue = 1.e+20f ;\n",
      "\t\ttas:cell_measures = \"area: areacella\" ;\n",
      "\n",
      "// global attributes:\n",
      "\t\t:Conventions = \"CF-1.12 CMIP-7.0\" ;\n",
      "\t\t:activity_id = \"CMIP\" ;\n",
      "\t\t:archive_id = \"WCRP\" ;\n",
      "\t\t:area_label = \"u\" ;\n",
      "\t\t:branch_method = \"standard\" ;\n",
      "\t\t:branch_time_in_child = 30. ;\n",
      "\t\t:branch_time_in_parent = 10800. ;\n",
      "\t\t:branding_suffix = \"tavg-h2m-hxy-u\" ;\n",
      "\t\t:creation_date = \"2025-10-16T14:36:16Z\" ;\n",
      "\t\t:cv_version = \"7.0.0.0\" ;\n",
      "\t\t:drs_specs = \"MIP-DRS7\" ;\n",
      "\t\t:end_year = \"2021 (TODO make clear it is end of 2021, not start)\" ;\n",
      "\t\t:experiment = \"Simulation of the recent past\" ;\n",
      "\t\t:experiment_id = \"historical\" ;\n",
      "\t\t:external_variables = \"areacella\" ;\n",
      "\t\t:forcing_index = \"f3\" ;\n",
      "\t\t:frequency = \"mon\" ;\n",
      "\t\t:grid = \"N96\" ;\n",
      "\t\t:grid_label = \"gn\" ;\n",
      "\t\t:history = \"2025-10-16T14:36:16Z ; CMOR rewrote data to be consistent with CMIP7, CF-1.12 CMIP-7.0 and CF standards.\" ;\n",
      "\t\t:horizontal_label = \"hxy\" ;\n",
      "\t\t:host_collection = \"CMIP7\" ;\n",
      "\t\t:initialization_index = \"i1\" ;\n",
      "\t\t:institution = \"Lawrence Livermore National Laboratory\" ;\n",
      "\t\t:institution_id = \"PCMDI\" ;\n",
      "\t\t:label = \"PCMDI-test 1.0\" ;\n",
      "\t\t:label_extended = \"PCMDI-test 1.0 (This entry is free text for users to contribute verbose information)\" ;\n",
      "\t\t:mip_era = \"CMIP7\" ;\n",
      "\t\t:nominal_resolution = \"250 km\" ;\n",
      "\t\t:parent_activity_id = \"CMIP\" ;\n",
      "\t\t:parent_experiment_id = \"piControl\" ;\n",
      "\t\t:parent_mip_era = \"CMIP7\" ;\n",
      "\t\t:parent_source_id = \"PCMDI-test-1-0\" ;\n",
      "\t\t:parent_time_units = \"days since 1850-01-01\" ;\n",
      "\t\t:parent_variant_label = \"r1i1p1f3\" ;\n",
      "\t\t:physics_index = \"p1\" ;\n",
      "\t\t:product = \"model-output\" ;\n",
      "\t\t:realization_index = \"r1\" ;\n",
      "\t\t:realm = \"atmos\" ;\n",
      "\t\t:region = \"GLB\" ;\n",
      "\t\t:release_year = \"1989\" ;\n",
      "\t\t:source = \"PCMDI-test 1.0 (1989): \\n\",\n",
      "\t\t\t\"aerosol: none\\n\",\n",
      "\t\t\t\"atmos: Earth1.0-gettingHotter (360 x 180 longitude/latitude; 50 levels; top level 0.1 mb)\\n\",\n",
      "\t\t\t\"atmosChem: none\\n\",\n",
      "\t\t\t\"land: Earth1.0\\n\",\n",
      "\t\t\t\"landIce: none\\n\",\n",
      "\t\t\t\"ocean: BlueMarble1.0-warming (360 x 180 longitude/latitude; 50 levels; top grid cell 0-10 m)\\n\",\n",
      "\t\t\t\"ocnBgchem: none\\n\",\n",
      "\t\t\t\"seaIce: Declining1.0-warming (360 x 180 longitude/latitude)\" ;\n",
      "\t\t:source_id = \"PCMDI-test-1-0\" ;\n",
      "\t\t:source_type = \"AOGCM CHEM BGC\" ;\n",
      "\t\t:start_year = \"1850\" ;\n",
      "\t\t:table_id = \"atmos\" ;\n",
      "\t\t:table_info = \"Creation Date:(2025-10-16 13:54:46) MD5:f1c3eadca96255f2ea17ed09c23b0f7d\" ;\n",
      "\t\t:temporal_label = \"tavg\" ;\n",
      "\t\t:title = \"PCMDI-test-1-0 output prepared for CMIP7\" ;\n",
      "\t\t:variable_id = \"tas\" ;\n",
      "\t\t:variant_label = \"r1i1p1f3\" ;\n",
      "\t\t:vertical_label = \"h2m\" ;\n",
      "\t\t:license = \"CC BY 4.0; CMIP7 data produced by PCMDI is licensed under a Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0/). Consult https://pcmdi.llnl.gov/CMIP7/TermsOfUse for terms of use governing CMIP7 output, including citation requirements and proper acknowledgment. The data producers and data providers make no warranty, either express or implied, including, but not limited to, warranties of merchantability and fitness for a particular purpose. All liabilities arising from the supply of the information (including any liability arising in negligence) are excluded to the fullest extent permitted by law.\" ;\n",
      "\t\t:cmor_version = \"3.13.0\" ;\n",
      "\t\t:tracking_id = \"hdl:21.14100/14c2595a-5c4b-45b8-b32a-5caa81a1eafb\" ;\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "!ncdump -h ./MIP-DRS7/CMIP7/CMIP/PCMDI/PCMDI-test-1-0/historical/r1i1p1f3/GLB/mon/tas/tavg-h2m-hxy-u/gn/*/tas_tavg-h2m-hxy-u_mon_GLB_gn_PCMDI-test-1-0_historical_r1i1p1f3_185001-199912.nc\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5fc612f-b007-4680-9a85-6e17212cea99",
   "metadata": {},
   "source": [
    "### Write pr (50 record chunks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "24e61273-0c32-43a1-ba39-68e12f1288d2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "slice(0, 50, None)\n",
      "slice(50, 100, None)\n",
      "slice(100, 150, None)\n",
      "slice(150, 200, None)\n",
      "slice(200, 250, None)\n",
      "slice(250, 300, None)\n",
      "slice(300, 350, None)\n",
      "slice(350, 400, None)\n",
      "slice(400, 450, None)\n",
      "slice(450, 500, None)\n",
      "slice(500, 550, None)\n",
      "slice(550, 600, None)\n",
      "slice(600, 650, None)\n",
      "slice(650, 700, None)\n",
      "slice(700, 750, None)\n",
      "slice(750, 800, None)\n",
      "slice(800, 850, None)\n",
      "slice(850, 900, None)\n",
      "slice(900, 950, None)\n",
      "slice(950, 1000, None)\n",
      "slice(1000, 1050, None)\n",
      "slice(1050, 1100, None)\n",
      "slice(1100, 1150, None)\n",
      "slice(1150, 1200, None)\n",
      "slice(1200, 1250, None)\n",
      "slice(1250, 1300, None)\n",
      "slice(1300, 1350, None)\n",
      "slice(1350, 1400, None)\n",
      "slice(1400, 1450, None)\n",
      "slice(1450, 1500, None)\n",
      "slice(1500, 1550, None)\n",
      "slice(1550, 1600, None)\n",
      "slice(1600, 1650, None)\n",
      "slice(1650, 1700, None)\n",
      "slice(1700, 1750, None)\n",
      "slice(1750, 1800, None)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'./MIP-DRS7//CMIP7//CMIP//PCMDI//PCMDI-test-1-0//historical//r1i1p1f3//GLB//mon//pr//tavg-u-hxy-u//gn//v20251016/pr_tavg-u-hxy-u_mon_GLB_gn_PCMDI-test-1-0_historical_r1i1p1f3_185001-199912.nc'"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# construct latitude and longitude coords\n",
    "cmorlat = cmor.axis(\"latitude\",\n",
    "                    coord_vals=pr_cube.coord('latitude').points,\n",
    "                    cell_bounds=pr_cube.coord('latitude').bounds,\n",
    "                    units=\"degrees_north\")\n",
    "cmorlon = cmor.axis(\"longitude\",\n",
    "                    coord_vals=pr_cube.coord('longitude').points,\n",
    "                    cell_bounds=pr_cube.coord('longitude').bounds,\n",
    "                    units=\"degrees_east\")\n",
    "# construct time coord in a way that we can update with points and bounds later\n",
    "cmortime = cmor.axis(\"time\",\n",
    "                        units=\"days since 1850-01-01\")\n",
    "# define CMOR variable object\n",
    "axes = [cmortime, cmorlat, cmorlon]\n",
    "variable = \"pr_tavg-u-hxy-u\"\n",
    "cmorpr = cmor.variable(variable, \"kg m-2 s-1\", axes)\n",
    "\n",
    "# manually apply cell measures\n",
    "region = DATASET_INFO['region']\n",
    "frequency = DATASET_INFO['frequency']\n",
    "cell_measures_key = \".\".join([realm] + variable.split(\"_\") + [frequency, region])\n",
    "\n",
    "# Check that cell_measures are valid ( option flags need to be manually replaced )\n",
    "variable_cell_measures = cell_measures[cell_measures_key]\n",
    "if variable_cell_measures in [\"::OPT\", \"::MODEL\"]:\n",
    "    raise RuntimeError(f\"found cell_measures '{variable_cell_measures}' which CMOR will not allow\")\n",
    "\n",
    "cmor.set_variable_attribute(cmorpr, \"cell_measures\", \"c\", variable_cell_measures)\n",
    "\n",
    "# slice up data into N time record chunks and push through CMOR.write\n",
    "N = 50\n",
    "for i in range(0, 1800, N):\n",
    "    s = slice(i, i + N)\n",
    "    print(s)\n",
    "    cube_slice = pr_cube[s]\n",
    "    cmor.write(\n",
    "        cmorpr,\n",
    "        tas_cube[s].data, \n",
    "        time_vals=tas_cube.coord('time').points[s], \n",
    "        time_bnds=tas_cube.coord('time').bounds[s])\n",
    "\n",
    "# close the file (sorts the full naming)\n",
    "cmor.close(cmorpr, file_name=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ffda90da-7dec-4837-a739-90f349c3d114",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "netcdf pr_tavg-u-hxy-u_mon_GLB_gn_PCMDI-test-1-0_historical_r1i1p1f3_185001-199912 {\n",
      "dimensions:\n",
      "\ttime = UNLIMITED ; // (1800 currently)\n",
      "\tlat = 144 ;\n",
      "\tlon = 192 ;\n",
      "\tbnds = 2 ;\n",
      "variables:\n",
      "\tdouble time(time) ;\n",
      "\t\ttime:bounds = \"time_bnds\" ;\n",
      "\t\ttime:units = \"days since 1850-01-01\" ;\n",
      "\t\ttime:calendar = \"360_day\" ;\n",
      "\t\ttime:axis = \"T\" ;\n",
      "\t\ttime:long_name = \"Time Intervals\" ;\n",
      "\t\ttime:standard_name = \"time\" ;\n",
      "\tdouble time_bnds(time, bnds) ;\n",
      "\tdouble lat(lat) ;\n",
      "\t\tlat:bounds = \"lat_bnds\" ;\n",
      "\t\tlat:units = \"degrees_north\" ;\n",
      "\t\tlat:axis = \"Y\" ;\n",
      "\t\tlat:long_name = \"Latitude\" ;\n",
      "\t\tlat:standard_name = \"latitude\" ;\n",
      "\tdouble lat_bnds(lat, bnds) ;\n",
      "\tdouble lon(lon) ;\n",
      "\t\tlon:bounds = \"lon_bnds\" ;\n",
      "\t\tlon:units = \"degrees_east\" ;\n",
      "\t\tlon:axis = \"X\" ;\n",
      "\t\tlon:long_name = \"Longitude\" ;\n",
      "\t\tlon:standard_name = \"longitude\" ;\n",
      "\tdouble lon_bnds(lon, bnds) ;\n",
      "\tfloat pr(time, lat, lon) ;\n",
      "\t\tpr:standard_name = \"precipitation_flux\" ;\n",
      "\t\tpr:long_name = \"Precipitation\" ;\n",
      "\t\tpr:units = \"kg m-2 s-1\" ;\n",
      "\t\tpr:cell_methods = \"area: time: mean\" ;\n",
      "\t\tpr:missing_value = 1.e+20f ;\n",
      "\t\tpr:_FillValue = 1.e+20f ;\n",
      "\t\tpr:cell_measures = \"area: areacella\" ;\n",
      "\n",
      "// global attributes:\n",
      "\t\t:Conventions = \"CF-1.12 CMIP-7.0\" ;\n",
      "\t\t:activity_id = \"CMIP\" ;\n",
      "\t\t:archive_id = \"WCRP\" ;\n",
      "\t\t:area_label = \"u\" ;\n",
      "\t\t:branch_method = \"standard\" ;\n",
      "\t\t:branch_time_in_child = 30. ;\n",
      "\t\t:branch_time_in_parent = 10800. ;\n",
      "\t\t:branding_suffix = \"tavg-u-hxy-u\" ;\n",
      "\t\t:creation_date = \"2025-10-16T14:36:35Z\" ;\n",
      "\t\t:cv_version = \"7.0.0.0\" ;\n",
      "\t\t:drs_specs = \"MIP-DRS7\" ;\n",
      "\t\t:end_year = \"2021 (TODO make clear it is end of 2021, not start)\" ;\n",
      "\t\t:experiment = \"Simulation of the recent past\" ;\n",
      "\t\t:experiment_id = \"historical\" ;\n",
      "\t\t:external_variables = \"areacella\" ;\n",
      "\t\t:forcing_index = \"f3\" ;\n",
      "\t\t:frequency = \"mon\" ;\n",
      "\t\t:grid = \"N96\" ;\n",
      "\t\t:grid_label = \"gn\" ;\n",
      "\t\t:history = \"2025-10-16T14:36:16Z ; CMOR rewrote data to be consistent with CMIP7, CF-1.12 CMIP-7.0 and CF standards.\" ;\n",
      "\t\t:horizontal_label = \"hxy\" ;\n",
      "\t\t:host_collection = \"CMIP7\" ;\n",
      "\t\t:initialization_index = \"i1\" ;\n",
      "\t\t:institution = \"Lawrence Livermore National Laboratory\" ;\n",
      "\t\t:institution_id = \"PCMDI\" ;\n",
      "\t\t:label = \"PCMDI-test 1.0\" ;\n",
      "\t\t:label_extended = \"PCMDI-test 1.0 (This entry is free text for users to contribute verbose information)\" ;\n",
      "\t\t:mip_era = \"CMIP7\" ;\n",
      "\t\t:nominal_resolution = \"250 km\" ;\n",
      "\t\t:parent_activity_id = \"CMIP\" ;\n",
      "\t\t:parent_experiment_id = \"piControl\" ;\n",
      "\t\t:parent_mip_era = \"CMIP7\" ;\n",
      "\t\t:parent_source_id = \"PCMDI-test-1-0\" ;\n",
      "\t\t:parent_time_units = \"days since 1850-01-01\" ;\n",
      "\t\t:parent_variant_label = \"r1i1p1f3\" ;\n",
      "\t\t:physics_index = \"p1\" ;\n",
      "\t\t:product = \"model-output\" ;\n",
      "\t\t:realization_index = \"r1\" ;\n",
      "\t\t:realm = \"atmos\" ;\n",
      "\t\t:region = \"GLB\" ;\n",
      "\t\t:release_year = \"1989\" ;\n",
      "\t\t:source = \"PCMDI-test 1.0 (1989): \\n\",\n",
      "\t\t\t\"aerosol: none\\n\",\n",
      "\t\t\t\"atmos: Earth1.0-gettingHotter (360 x 180 longitude/latitude; 50 levels; top level 0.1 mb)\\n\",\n",
      "\t\t\t\"atmosChem: none\\n\",\n",
      "\t\t\t\"land: Earth1.0\\n\",\n",
      "\t\t\t\"landIce: none\\n\",\n",
      "\t\t\t\"ocean: BlueMarble1.0-warming (360 x 180 longitude/latitude; 50 levels; top grid cell 0-10 m)\\n\",\n",
      "\t\t\t\"ocnBgchem: none\\n\",\n",
      "\t\t\t\"seaIce: Declining1.0-warming (360 x 180 longitude/latitude)\" ;\n",
      "\t\t:source_id = \"PCMDI-test-1-0\" ;\n",
      "\t\t:source_type = \"AOGCM CHEM BGC\" ;\n",
      "\t\t:start_year = \"1850\" ;\n",
      "\t\t:table_id = \"atmos\" ;\n",
      "\t\t:table_info = \"Creation Date:(2025-10-16 13:54:46) MD5:f1c3eadca96255f2ea17ed09c23b0f7d\" ;\n",
      "\t\t:temporal_label = \"tavg\" ;\n",
      "\t\t:title = \"PCMDI-test-1-0 output prepared for CMIP7\" ;\n",
      "\t\t:variable_id = \"pr\" ;\n",
      "\t\t:variant_label = \"r1i1p1f3\" ;\n",
      "\t\t:vertical_label = \"u\" ;\n",
      "\t\t:license = \"CC BY 4.0; CMIP7 data produced by PCMDI is licensed under a Creative Commons Attribution 4.0 International License (https://creativecommons.org/licenses/by/4.0/). Consult https://pcmdi.llnl.gov/CMIP7/TermsOfUse for terms of use governing CMIP7 output, including citation requirements and proper acknowledgment. The data producers and data providers make no warranty, either express or implied, including, but not limited to, warranties of merchantability and fitness for a particular purpose. All liabilities arising from the supply of the information (including any liability arising in negligence) are excluded to the fullest extent permitted by law.\" ;\n",
      "\t\t:cmor_version = \"3.13.0\" ;\n",
      "\t\t:tracking_id = \"hdl:21.14100/562b67c4-037c-4759-af3e-176928639811\" ;\n",
      "}\n"
     ]
    }
   ],
   "source": [
    "!ncdump -h ./MIP-DRS7/CMIP7/CMIP/PCMDI/PCMDI-test-1-0/historical/r1i1p1f3/GLB/mon/pr/tavg-u-hxy-u/gn/*/pr_tavg-u-hxy-u_mon_GLB_gn_PCMDI-test-1-0_historical_r1i1p1f3_185001-199912.nc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "abd84c32-15a1-454a-b03f-3f3a83142f0c",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "CMOR-3.13",
   "language": "python",
   "name": "cmor-3.13"
  },
  "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.13.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
