From 0f401a5c96f9e6219583fcc01d8c59034d966bfe Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 18 Aug 2025 04:28:10 -0500 Subject: [PATCH 1/2] Lint and format landice.create --- conda_package/mpas_tools/landice/create.py | 530 ++++++++++++++------- 1 file changed, 345 insertions(+), 185 deletions(-) diff --git a/conda_package/mpas_tools/landice/create.py b/conda_package/mpas_tools/landice/create.py index 403f829b6..e79b9403f 100755 --- a/conda_package/mpas_tools/landice/create.py +++ b/conda_package/mpas_tools/landice/create.py @@ -1,13 +1,14 @@ import sys +from datetime import datetime +from optparse import OptionParser + import numpy from netCDF4 import Dataset -from optparse import OptionParser -from datetime import datetime from mpas_tools.cime.constants import constants -def create_from_generic_mpas_grid(): +def create_from_generic_mpas_grid(): # noqa C901 """ Script to create a grid with land ice variables from an MPAS grid. Currently variable attributes are not copied. @@ -18,66 +19,96 @@ def create_from_generic_mpas_grid(): # earth radius, if needed sphere_radius = constants['SHR_CONST_REARTH'] - print("** Gathering information. (Invoke with --help for more details. " - "All arguments are optional)") + print( + '** Gathering information. (Invoke with --help for more details. ' + 'All arguments are optional)' + ) parser = OptionParser() parser.add_option( - "-i", "--in", dest="fileinName", - help="input filename. Defaults to 'grid.nc'", - metavar="FILENAME") + '-i', + '--in', + dest='fileinName', + help="input filename. Defaults to 'grid.nc'", + metavar='FILENAME', + ) parser.add_option( - "-o", "--out", dest="fileoutName", - help="output filename. Defaults to 'landice_grid.nc'", - metavar="FILENAME") + '-o', + '--out', + dest='fileoutName', + help="output filename. Defaults to 'landice_grid.nc'", + metavar='FILENAME', + ) parser.add_option( - "-l", "--level", dest="levels", - help="Number of vertical levels to use in the output file. " - "Defaults to the number in the input file", - metavar="FILENAME") + '-l', + '--level', + dest='levels', + help='Number of vertical levels to use in the output file. ' + 'Defaults to the number in the input file', + metavar='FILENAME', + ) parser.add_option( - "-v", "--vert", dest="vertMethod", - help="Method of vertical layer spacing: uniform, glimmer. " - "Glimmer spacing follows Eq. 35 of Rutt, I. C., M. Hagdorn, " - "N. R. J. Hulton, and A. J. Payne (2009), The Glimmer community " - "ice sheet model, J. Geophys. Res., 114, F02004, " - "doi:10.1029/2008JF001015", - default='glimmer', metavar="FILENAME") + '-v', + '--vert', + dest='vertMethod', + help='Method of vertical layer spacing: uniform, glimmer. ' + 'Glimmer spacing follows Eq. 35 of Rutt, I. C., M. Hagdorn, ' + 'N. R. J. Hulton, and A. J. Payne (2009), The Glimmer community ' + 'ice sheet model, J. Geophys. Res., 114, F02004, ' + 'doi:10.1029/2008JF001015', + default='glimmer', + metavar='FILENAME', + ) parser.add_option( - "--beta", dest="beta", action="store_true", - help="DEPRECATED") + '--beta', dest='beta', action='store_true', help='DEPRECATED' + ) parser.add_option( - "--effecpress", dest="effecpress", action="store_true", - help="DEPRECATED") + '--effecpress', + dest='effecpress', + action='store_true', + help='DEPRECATED', + ) parser.add_option( - "--diri", dest="dirichlet", action="store_true", - help="Use this flag to include the fields 'dirichletVelocityMask', " - "'uReconstructX', 'uReconstructY' needed for specifying Dirichlet " - "velocity boundary conditions in the resulting file.") + '--diri', + dest='dirichlet', + action='store_true', + help="Use this flag to include the fields 'dirichletVelocityMask', " + "'uReconstructX', 'uReconstructY' needed for specifying Dirichlet " + 'velocity boundary conditions in the resulting file.', + ) parser.add_option( - "--thermal", dest="thermal", action="store_true", - help="Use this flag to include the fields 'temperature', " - "'surfaceAirTemperature', 'basalHeatFlux' needed for specifying " - "thermal initial conditions in the resulting file.") + '--thermal', + dest='thermal', + action='store_true', + help="Use this flag to include the fields 'temperature', " + "'surfaceAirTemperature', 'basalHeatFlux' needed for specifying " + 'thermal initial conditions in the resulting file.', + ) parser.add_option( - "--hydro", dest="hydro", action="store_true", - help="Use this flag to include the fields 'waterThickness', " - "'tillWaterThickness', 'basalMeltInput', 'externalWaterInput', " - "'frictionAngle', 'waterPressure', 'waterFluxMask' needed for " - "specifying hydro initial conditions in the resulting file.") + '--hydro', + dest='hydro', + action='store_true', + help="Use this flag to include the fields 'waterThickness', " + "'tillWaterThickness', 'basalMeltInput', 'externalWaterInput', " + "'frictionAngle', 'waterPressure', 'waterFluxMask' needed for " + 'specifying hydro initial conditions in the resulting file.', + ) parser.add_option( - "--obs", dest="obs", action="store_true", - help="Use this flag to include the observational fields " - "observedSurfaceVelocityX, observedSurfaceVelocityY, " - "observedSurfaceVelocityUncertainty, observedThicknessTendency, " - "observedThicknessTendencyUncertainty, thicknessUncertainty " - "needed doing optimizations constrained by obs velocities.") + '--obs', + dest='obs', + action='store_true', + help='Use this flag to include the observational fields ' + 'observedSurfaceVelocityX, observedSurfaceVelocityY, ' + 'observedSurfaceVelocityUncertainty, observedThicknessTendency, ' + 'observedThicknessTendencyUncertainty, thicknessUncertainty ' + 'needed doing optimizations constrained by obs velocities.', + ) options, args = parser.parse_args() if not options.fileinName: print("No input filename specified, so using 'grid.nc'.") options.fileinName = 'grid.nc' else: - print("Input file is: {}".format(options.fileinName)) + print(f'Input file is: {options.fileinName}') if not options.fileoutName: print("No output filename specified, so using 'landice_grid.nc'.") options.fileoutName = 'landice_grid.nc' @@ -88,25 +119,26 @@ def create_from_generic_mpas_grid(): filein = Dataset(options.fileinName, 'r') # Define the new file to be output - fileout = Dataset(options.fileoutName, "w", format=filein.file_format) + fileout = Dataset(options.fileoutName, 'w', format=filein.file_format) # ============================================ # Copy over all of the netcdf global attributes # ============================================ # Do this first as doing it last is slow for big files since adding # attributes forces the contents to get reorganized. - print("---- Copying global attributes from input file to output file ----") + print('---- Copying global attributes from input file to output file ----') for name in filein.ncattrs(): # sphere radius needs to be set to that of the earth if on a sphere - if name == 'sphere_radius' and \ - getattr(filein, 'on_a_sphere') == "YES ": - setattr(fileout, 'sphere_radius', sphere_radius) + if ( + name == 'sphere_radius' + and filein.on_a_sphere == 'YES ' + ): + fileout.sphere_radius = sphere_radius print(f'Set global attribute sphere_radius = {sphere_radius}') elif name == 'history': # Update history attribute of netCDF file - newhist = '\n'.join([getattr(filein, 'history'), - ' '.join(sys.argv[:])]) - setattr(fileout, 'history', newhist) + newhist = '\n'.join([filein.history, ' '.join(sys.argv[:])]) + fileout.history = newhist else: # Otherwise simply copy the attr setattr(fileout, name, getattr(filein, name)) @@ -114,7 +146,7 @@ def create_from_generic_mpas_grid(): # Update history attribute of netCDF file if we didn't above if not hasattr(fileout, 'history'): - setattr(fileout, 'history', sys.argv[:]) + fileout.history = sys.argv[:] fileout.sync() # make a space in stdout before further output @@ -133,31 +165,35 @@ def create_from_generic_mpas_grid(): # for how to deal with assigning values to a variable with a # unlimited dimension. Special handling is needed with the netCDF # module. - print("---- Copying dimensions from input file to output file ----") + print('---- Copying dimensions from input file to output file ----') for dim in filein.dimensions.keys(): if dim == 'nTracers': pass # Do nothing - we don't want this dimension - elif (dim == 'nVertInterfaces'): + elif dim == 'nVertInterfaces': pass # Do nothing - this dimension will be handled below - else: # Copy over all other dimensions + else: # Copy over all other dimensions if dim == 'Time': # netCDF4 won't properly get this with the command below (you # need to use the isunlimited method) dimvalue = None - elif (dim == 'nVertLevels'): + elif dim == 'nVertLevels': if options.levels is None: # If nVertLevels is in the input file, and a value for it # was not specified on the command line, then use the value # from the file (do nothing here) - print(f"Using nVertLevels from the intput file: " - f"{len(filein.dimensions[dim])}") + print( + f'Using nVertLevels from the intput file: ' + f'{len(filein.dimensions[dim])}' + ) dimvalue = len(filein.dimensions[dim]) else: # if nVertLevels is in the input file, but a value WAS # specified on the command line, then use the command line # value - print(f"Using nVertLevels specified on the command line: " - f"{int(options.levels)}") + print( + f'Using nVertLevels specified on the command line: ' + f'{int(options.levels)}' + ) dimvalue = int(options.levels) else: dimvalue = len(filein.dimensions[dim]) @@ -167,20 +203,27 @@ def create_from_generic_mpas_grid(): # here. if 'nVertLevels' not in fileout.dimensions: if options.levels is None: - print("nVertLevels not in input file and not specified. Using " - "default value of 10.") + print( + 'nVertLevels not in input file and not specified. Using ' + 'default value of 10.' + ) fileout.createDimension('nVertLevels', 10) else: - print(f"Using nVertLevels specified on the command line: " - f"{int(options.levels)}") + print( + f'Using nVertLevels specified on the command line: ' + f'{int(options.levels)}' + ) fileout.createDimension('nVertLevels', int(options.levels)) # Also create the nVertInterfaces dimension, even if none of the variables # require it. # nVertInterfaces = nVertLevels + 1 - fileout.createDimension('nVertInterfaces', - len(fileout.dimensions['nVertLevels']) + 1) - print(f'Added new dimension nVertInterfaces to output file with value of ' - f'{len(fileout.dimensions["nVertInterfaces"])}') + fileout.createDimension( + 'nVertInterfaces', len(fileout.dimensions['nVertLevels']) + 1 + ) + print( + f'Added new dimension nVertInterfaces to output file with value of ' + f'{len(fileout.dimensions["nVertInterfaces"])}' + ) fileout.sync() # include an extra blank line here @@ -189,49 +232,93 @@ def create_from_generic_mpas_grid(): # ============================================ # Copy over all of the required grid variables to the new file # ============================================ - print("Beginning to copy mesh variables to output file.") - vars2copy = ['latCell', 'lonCell', 'xCell', 'yCell', 'zCell', - 'indexToCellID', 'latEdge', 'lonEdge', 'xEdge', 'yEdge', - 'zEdge', 'indexToEdgeID', 'latVertex', 'lonVertex', 'xVertex', - 'yVertex', 'zVertex', 'indexToVertexID', 'cellsOnEdge', - 'nEdgesOnCell', 'nEdgesOnEdge', 'edgesOnCell', 'edgesOnEdge', - 'weightsOnEdge', 'dvEdge', 'dcEdge', 'angleEdge', 'areaCell', - 'areaTriangle', 'cellsOnCell', 'verticesOnCell', - 'verticesOnEdge', 'edgesOnVertex', 'cellsOnVertex', - 'kiteAreasOnVertex'] + print('Beginning to copy mesh variables to output file.') + vars2copy = [ + 'latCell', + 'lonCell', + 'xCell', + 'yCell', + 'zCell', + 'indexToCellID', + 'latEdge', + 'lonEdge', + 'xEdge', + 'yEdge', + 'zEdge', + 'indexToEdgeID', + 'latVertex', + 'lonVertex', + 'xVertex', + 'yVertex', + 'zVertex', + 'indexToVertexID', + 'cellsOnEdge', + 'nEdgesOnCell', + 'nEdgesOnEdge', + 'edgesOnCell', + 'edgesOnEdge', + 'weightsOnEdge', + 'dvEdge', + 'dcEdge', + 'angleEdge', + 'areaCell', + 'areaTriangle', + 'cellsOnCell', + 'verticesOnCell', + 'verticesOnEdge', + 'edgesOnVertex', + 'cellsOnVertex', + 'kiteAreasOnVertex', + ] # Add these optional fields if they exist in the input file - for optionalVar in ['meshDensity', 'gridSpacing', 'cellQuality', - 'triangleQuality', 'triangleAngleQuality', - 'obtuseTriangle']: + for optionalVar in [ + 'meshDensity', + 'gridSpacing', + 'cellQuality', + 'triangleQuality', + 'triangleAngleQuality', + 'obtuseTriangle', + ]: if optionalVar in filein.variables: vars2copy.append(optionalVar) - for varname in vars2copy: - print("- ", end='') - print("|") + for _ in vars2copy: + print('- ', end='') + print('|') for varname in vars2copy: thevar = filein.variables[varname] datatype = thevar.dtype newVar = fileout.createVariable(varname, datatype, thevar.dimensions) - if filein.on_a_sphere == "YES ": - if varname in ('xCell', 'yCell', 'zCell', 'xEdge', 'yEdge', - 'zEdge', 'xVertex', 'yVertex', 'zVertex', 'dvEdge', - 'dcEdge'): + if filein.on_a_sphere == 'YES ': + if varname in ( + 'xCell', + 'yCell', + 'zCell', + 'xEdge', + 'yEdge', + 'zEdge', + 'xVertex', + 'yVertex', + 'zVertex', + 'dvEdge', + 'dcEdge', + ): newVar[:] = thevar[:] * sphere_radius / filein.sphere_radius elif varname in ('areaCell', 'areaTriangle', 'kiteAreasOnVertex'): newVar[:] = ( - thevar[:] * (sphere_radius / filein.sphere_radius)**2) + thevar[:] * (sphere_radius / filein.sphere_radius) ** 2 + ) else: newVar[:] = thevar[:] else: # not on a sphere newVar[:] = thevar[:] del newVar, thevar - sys.stdout.write("* ") + sys.stdout.write('* ') sys.stdout.flush() fileout.sync() - print("|") - print("Finished copying mesh variables to output file.\n") + print('|') + print('Finished copying mesh variables to output file.\n') # ============================================ # Create the land ice variables (all the shallow water vars in the input @@ -247,9 +334,9 @@ def create_from_generic_mpas_grid(): # seems to be fine. # layerThicknessFractions - layerThicknessFractions = fileout.createVariable('layerThicknessFractions', - datatype, - ('nVertLevels', )) + layerThicknessFractions = fileout.createVariable( + 'layerThicknessFractions', datatype, ('nVertLevels',) + ) layerThicknessFractionsData = numpy.zeros(layerThicknessFractions.shape) # Assign default values to layerThicknessFractions. By default they will # be uniform fractions. Users can modify them in a subsequent step, but @@ -262,18 +349,38 @@ def create_from_generic_mpas_grid(): nInterfaces = nVertLevels + 1 layerInterfaces = numpy.zeros((nInterfaces,)) for k in range(nInterfaces): - layerInterfaces[k] = 4.0 / 3.0 * (1.0 - ((k + 1.0 - 1.0) / (nInterfaces - 1.0) + 1.0)**-2) + layerInterfaces[k] = ( + 4.0 + / 3.0 + * (1.0 - ((k + 1.0 - 1.0) / (nInterfaces - 1.0) + 1.0) ** -2) + ) for k in range(nVertLevels): layerThicknessFractionsData[k] = ( - layerInterfaces[k+1] - layerInterfaces[k]) - print(f"Setting layerThicknessFractions to: " - f"{layerThicknessFractionsData}") + layerInterfaces[k + 1] - layerInterfaces[k] + ) + print( + f'Setting layerThicknessFractions to: ' + f'{layerThicknessFractionsData}' + ) else: - raise ValueError(f'Unknown method for vertical spacing method ' - f'(--vert): {options.vertMethod}') + raise ValueError( + f'Unknown method for vertical spacing method ' + f'(--vert): {options.vertMethod}' + ) # explictly specify layer fractions - # layerThicknessFractionsData[:] = [0.1663,0.1516,0.1368,0.1221,0.1074,0.0926,0.0779,0.0632,0.0484,0.0337] + # layerThicknessFractionsData[:] = [ + # 0.1663, + # 0.1516, + # 0.1368, + # 0.1221, + # 0.1074, + # 0.0926, + # 0.0779, + # 0.0632, + # 0.0484, + # 0.0337, + # ] layerThicknessFractions[:] = layerThicknessFractionsData[:] @@ -286,160 +393,213 @@ def create_from_generic_mpas_grid(): # These landice variables are stored in the mesh currently, and therefore # do not have a time dimension. It may make sense to eventually move them # to state. - newvar = fileout.createVariable('bedTopography', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'bedTopography', datatype, ('Time', 'nCells') + ) newvar[:] = numpy.zeros(newvar.shape) - newvar = fileout.createVariable('sfcMassBal', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable('sfcMassBal', datatype, ('Time', 'nCells')) newvar[:] = numpy.zeros(newvar.shape) - newvar = fileout.createVariable('floatingBasalMassBal', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'floatingBasalMassBal', datatype, ('Time', 'nCells') + ) newvar[:] = numpy.zeros(newvar.shape) - print('Added default variables: thickness, temperature, bedTopography, ' - 'sfcMassBal, floatingBasalMassBal') + print( + 'Added default variables: thickness, temperature, bedTopography, ' + 'sfcMassBal, floatingBasalMassBal' + ) - newvar = fileout.createVariable('beta', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable('beta', datatype, ('Time', 'nCells')) # Give a default beta that won't have much sliding. newvar[:] = 1.0e8 print('Added variable: beta') - newvar = fileout.createVariable('muFriction', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable('muFriction', datatype, ('Time', 'nCells')) # Give a default mu that won't have much sliding. newvar[:] = 1.0e8 print('Added variable: muFriction') - newvar = fileout.createVariable('effectivePressure', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'effectivePressure', datatype, ('Time', 'nCells') + ) # Give a default effective pressure of 1.0 so that, for the linear sliding # law, beta = mu*effecpress = mu. newvar[:] = 1.0 print('Added variable: effectivePressure') - newvar = fileout.createVariable('stiffnessFactor', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'stiffnessFactor', datatype, ('Time', 'nCells') + ) # Give default value newvar[:] = 1.0 print('Added variable: stiffnessFactor') - newvar = fileout.createVariable('eigencalvingParameter', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'eigencalvingParameter', datatype, ('Time', 'nCells') + ) # Give default value for eigencalvingParameter newvar[:] = 3.14e16 print('Added variable: eigencalvingParameter') - newvar = fileout.createVariable('groundedVonMisesThresholdStress', - datatype, ('Time', 'nCells')) + newvar = fileout.createVariable( + 'groundedVonMisesThresholdStress', datatype, ('Time', 'nCells') + ) # Give default value newvar[:] = 1.0e6 print('Added variable: groundedVonMisesThresholdStress') - newvar = fileout.createVariable('floatingVonMisesThresholdStress', - datatype, ('Time', 'nCells')) + newvar = fileout.createVariable( + 'floatingVonMisesThresholdStress', datatype, ('Time', 'nCells') + ) # Give default value newvar[:] = 1.0e6 print('Added variable: floatingVonMisesThresholdStress') - newvar = fileout.createVariable('iceMask', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable('iceMask', datatype, ('Time', 'nCells')) newvar[:] = 0 print('Added variable: iceMask') if options.dirichlet: - newvar = fileout.createVariable('dirichletVelocityMask', datatypeInt, - ('Time', 'nCells', 'nVertInterfaces')) + newvar = fileout.createVariable( + 'dirichletVelocityMask', + datatypeInt, + ('Time', 'nCells', 'nVertInterfaces'), + ) # default: no Dirichlet b.c. newvar[:] = 0 - newvar = fileout.createVariable('uReconstructX', datatype, - ('Time', 'nCells', 'nVertInterfaces',)) + newvar = fileout.createVariable( + 'uReconstructX', + datatype, + ( + 'Time', + 'nCells', + 'nVertInterfaces', + ), + ) newvar[:] = 0.0 - newvar = fileout.createVariable('uReconstructY', datatype, - ('Time', 'nCells', 'nVertInterfaces',)) + newvar = fileout.createVariable( + 'uReconstructY', + datatype, + ( + 'Time', + 'nCells', + 'nVertInterfaces', + ), + ) newvar[:] = 0.0 - print('Added optional dirichlet variables: dirichletVelocityMask, ' - 'uReconstructX, uReconstructY') + print( + 'Added optional dirichlet variables: dirichletVelocityMask, ' + 'uReconstructX, uReconstructY' + ) if options.thermal: - newvar = fileout.createVariable('temperature', datatype, - ('Time', 'nCells', 'nVertLevels')) + newvar = fileout.createVariable( + 'temperature', datatype, ('Time', 'nCells', 'nVertLevels') + ) # Give default value for temperate ice newvar[:] = 273.15 - newvar = fileout.createVariable('surfaceAirTemperature', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'surfaceAirTemperature', datatype, ('Time', 'nCells') + ) # Give default value for temperate ice newvar[:] = 273.15 - newvar = fileout.createVariable('basalHeatFlux', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'basalHeatFlux', datatype, ('Time', 'nCells') + ) # Default to none (W/m2) newvar[:] = 0.0 - print('Added optional thermal variables: temperature, ' - 'surfaceAirTemperature, basalHeatFlux') + print( + 'Added optional thermal variables: temperature, ' + 'surfaceAirTemperature, basalHeatFlux' + ) if options.hydro: - newvar = fileout.createVariable('waterThickness', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'waterThickness', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('tillWaterThickness', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'tillWaterThickness', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('basalMeltInput', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'basalMeltInput', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('externalWaterInput', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'externalWaterInput', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('frictionAngle', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'frictionAngle', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('waterPressure', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'waterPressure', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('waterFluxMask', 'i', - ('Time', 'nEdges')) + newvar = fileout.createVariable( + 'waterFluxMask', 'i', ('Time', 'nEdges') + ) newvar[:] = 0.0 - print('Added optional hydro variables: waterThickness, ' - 'tillWaterThickness, meltInput, frictionAngle, waterPressure, ' - 'waterFluxMask') + print( + 'Added optional hydro variables: waterThickness, ' + 'tillWaterThickness, meltInput, frictionAngle, waterPressure, ' + 'waterFluxMask' + ) if options.obs: - newvar = fileout.createVariable('observedSurfaceVelocityX', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'observedSurfaceVelocityX', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('observedSurfaceVelocityY', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'observedSurfaceVelocityY', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('observedSurfaceVelocityUncertainty', - datatype, ('Time', 'nCells')) + newvar = fileout.createVariable( + 'observedSurfaceVelocityUncertainty', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('observedThicknessTendency', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'observedThicknessTendency', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - newvar = fileout.createVariable('observedThicknessTendencyUncertainty', - datatype, ('Time', 'nCells')) + newvar = fileout.createVariable( + 'observedThicknessTendencyUncertainty', + datatype, + ('Time', 'nCells'), + ) newvar[:] = 0.0 - newvar = fileout.createVariable('thicknessUncertainty', datatype, - ('Time', 'nCells')) + newvar = fileout.createVariable( + 'thicknessUncertainty', datatype, ('Time', 'nCells') + ) newvar[:] = 0.0 - print('Added optional velocity optimization variables: ' - 'observedSurfaceVelocityX, observedSurfaceVelocityY, ' - 'observedSurfaceVelocityUncertainty, observedThicknessTendency, ' - 'observedThicknessTendencyUncertainty, thicknessUncertainty') + print( + 'Added optional velocity optimization variables: ' + 'observedSurfaceVelocityX, observedSurfaceVelocityY, ' + 'observedSurfaceVelocityUncertainty, observedThicknessTendency, ' + 'observedThicknessTendencyUncertainty, thicknessUncertainty' + ) # Update history attribute of netCDF file - thiscommand = datetime.now().strftime("%a %b %d %H:%M:%S %Y") + ": " + \ - " ".join(sys.argv[:]) + thiscommand = ( + datetime.now().strftime('%a %b %d %H:%M:%S %Y') + + ': ' + + ' '.join(sys.argv[:]) + ) if hasattr(fileout, 'history'): - newhist = '\n'.join([thiscommand, getattr(fileout, 'history')]) + newhist = '\n'.join([thiscommand, fileout.history]) else: newhist = thiscommand - setattr(fileout, 'history', newhist) + fileout.history = newhist - print("Completed creating land ice variables in new file. Now syncing to " - "file.") + print( + 'Completed creating land ice variables in new file. Now syncing to ' + 'file.' + ) fileout.sync() filein.close() fileout.close() - print('\n** Successfully created {}.**'.format(options.fileoutName)) + print(f'\n** Successfully created {options.fileoutName}.**') From 5d7c56ede6aabb45289b44ceaef587f8cbc1535f Mon Sep 17 00:00:00 2001 From: Xylar Asay-Davis Date: Mon, 18 Aug 2025 04:35:29 -0500 Subject: [PATCH 2/2] Ensure `Time` dim is added to landice initial condition MPAS meshes include an empty, unlimited `Time` dimension but the latest NetCDF4 drops this dimension since no variable use it. the `create_from_generic_mpas_grid()` funciton in `landice.create` was taking advantage of `Time` being a dimension in the MPAS mesh but this should no longer be assumed. This merge fixes that assumption by explicitly adding `Time` to the list of dimensions to create if it is not already in the input dataset. --- conda_package/mpas_tools/landice/create.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/conda_package/mpas_tools/landice/create.py b/conda_package/mpas_tools/landice/create.py index e79b9403f..9f8328f8a 100755 --- a/conda_package/mpas_tools/landice/create.py +++ b/conda_package/mpas_tools/landice/create.py @@ -166,7 +166,14 @@ def create_from_generic_mpas_grid(): # noqa C901 # unlimited dimension. Special handling is needed with the netCDF # module. print('---- Copying dimensions from input file to output file ----') - for dim in filein.dimensions.keys(): + + create_dims = list(filein.dimensions.keys()) + + # We will add variables with Time as a dimension so we need it + if 'Time' not in create_dims: + create_dims.append('Time') + + for dim in create_dims: if dim == 'nTracers': pass # Do nothing - we don't want this dimension elif dim == 'nVertInterfaces':