Skip to content
Draft
46 changes: 45 additions & 1 deletion python/ctsm/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

import logging
import os
import stat
import sys
import glob
import string
import re
import pdb
import tempfile
import subprocess

from datetime import date, timedelta, datetime
from getpass import getuser
Expand Down Expand Up @@ -191,6 +194,7 @@ def write_output(file, file_in, file_out, file_type):
"""

# update attributes
logger.info("Updating metadata: %s", file_out)
title = "Modified " + file_type + " file"
summary = "Modified " + file_type + " file"
contact = "N/A"
Expand All @@ -205,11 +209,51 @@ def write_output(file, file_in, file_out, file_type):
description=description,
)

logger.info("Writing: %s", file_out)
# mode 'w' overwrites file if it exists
file.to_netcdf(path=file_out, mode="w", format="NETCDF3_64BIT")
file.to_netcdf(path=file_out, mode="w", format="NETCDF4_CLASSIC")
logger.info("Successfully created: %s", file_out)
file.close()

logger.info("Trying to convert to NETCDF3_CLASSIC: %s", file_out)
if convert_netcdf_to_classic(file_out):
logger.info("Conversion succeeded")
else:
logger.info("Conversion failed, perhaps because nccopy wasn't found in your shell")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Check whether nccopy is available in shell before the initial file.to_netcdf() call. If it's not, just skip straight to old behavior of "NETCDF3_64BIT".
  • If conversion fails, try saving again via file.to_netcdf(), this time straight to "NETCDF3_64BIT".

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @samsrabin I'm just wondering the reasons behind the convert to classic being done here?

I don't know of any compelling reasons to prefer classic over other formats. And classic has some pretty strong restrictions. And it seems preferable to me to write it out in the preferred format from the get go rather than convert. But I would like to hear the thinking here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think I meant for this all to be netCDF-3 64-bit. Will fix.



def convert_netcdf_to_classic(filepath):
"""
Try to convert netCDF to netCDF-3 Classic format using nccopy.
"""
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

convert_netcdf_to_classic() should be moved to netcdf_utils and unit-tested.


# Get temporary file path
dirpath = os.path.dirname(filepath)
with tempfile.NamedTemporaryFile(delete=False, dir=dirpath, suffix=".nc") as tmp:
temp_path = tmp.name

try:
subprocess.run(["nccopy", "-3", filepath, temp_path], check=True)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use xarray's Dataset.to_netcdf() instead?

copy_permissions(filepath, temp_path) # nccopy doesn't preserve permissions
os.replace(temp_path, filepath)
return True
except subprocess.CalledProcessError:
return False


def copy_permissions(src_file, dst_file):
"""
Copy file permissions from src to dest
"""
# Get the mode (permissions) of the source file
src_mode = os.stat(src_file).st_mode

# Extract the permission bits
permissions = stat.S_IMODE(src_mode)

# Apply them to the destination file
os.chmod(dst_file, permissions)


def get_isosplit(iso_string, split):
"""
Expand Down