def apply_fix(self): """ Fix the affected file This should replicate the Unix commands: ncap2 -h -s 'tos=tos-273.15f' filename.nc filename.nc.temp rm filename.nc mv filename.nc.temp filename.nc ncatted -h -a units,tos,m,c,'degC' filename.nc """ if not self._is_kelvin(): raise ExistingAttributeError(self.filename, 'units', 'Units are not K.') self.command = (f"ncap2 -h -s '{self.variable_name}=" f"{self.variable_name}-273.15f'") self._run_nco_command(Ncap2Error) units_command = ( f"ncatted -h -a units,{self.variable_name},m,c,'degC' " f"{os.path.join(self.directory, self.filename)}") try: run_command(units_command) except Exception: raise NcattedError( type(self).__name__, self.filename, units_command, traceback.format_exc())
def _run_ncatted(self, nco_mode): """ Run the command :param str nco_mode: The mode to run nco in. """ for attr_name in [ 'attribute_name', 'attribute_visibility', 'new_value' ]: attr_value = getattr(self, attr_name, None) if attr_value is None: raise InstanceVariableNotDefinedError( type(self).__name__, attr_name) # Aiming for: # ncatted -h -a branch_time_in_parent,global,o,d,10800.0 quote_mark = "'" if isinstance(self.new_value, str) else "" cmd = 'ncatted -h -a {},{},{},{},{}{}{} {}'.format( self.attribute_name, self.attribute_visibility, nco_mode, self.attribute_type, quote_mark, self.new_value, quote_mark, os.path.join(self.directory, self.filename)) try: run_command(cmd) except Exception: raise NcattedError( type(self).__name__, self.filename, cmd, traceback.format_exc())
def _set_attribute(filepath, attr_name, attr_value): """ Overwrite the specified global attribute value on the specified netCDF file. :param str filepath: The name of the netCDF file to update :param str attr_name: The name of the attribute to set :param str attr_value: The new value of the specified attribute :raises RunTimeError: if ncatted doesn't complete successfully """ cmd = "ncatted -h -a {},global,o,c,'{}' {}".format(attr_name, attr_value, filepath) run_command(cmd)
def apply_fix(self): """ Use cdo to set the reference time. """ self.command = f"ncks -h -A -v height {self.reference_file}" self._run_ncks_command() units_command = (f"ncatted -h -a coordinates,{self.variable_name},o,c," f"'height' " f"{os.path.join(self.directory, self.filename)}") try: run_command(units_command) except Exception: raise NcattedError( type(self).__name__, self.filename, units_command, traceback.format_exc())
def apply_fix(self): """ Run ncpdq and then swap the columns in lat_bnds. """ # check that the latitude is decreasing and that the fix is actually # needed if not self._is_lat_decreasing(): raise ExistingAttributeError(self.filename, 'latitude', 'Latitude is not decreasing.') self.command = 'ncpdq -a -lat' self._run_nco_command(NcpdqError) original_nc = os.path.join(self.directory, self.filename) bnds_file = original_nc + '.bnds' corrected_bnds_file = bnds_file + '_corr' # Remove any temporary files left over from a previous failed # run as they can prevent ncks and ncpdq from running. for filename in (bnds_file, corrected_bnds_file): if os.path.exists(filename): os.remove(filename) commands = [ # Copy lat_bnds to a new file f'ncks -v lat_bnds {original_nc} {bnds_file}', # Swap the colums f'ncpdq -a -bnds {bnds_file} {corrected_bnds_file}', # Remove history from lat_bnds as this is pasted back into the file f'ncatted -h -a history,global,d,, {corrected_bnds_file}', # Paste the fixed bnds back into the original file f'ncks -A -v lat_bnds {corrected_bnds_file} {original_nc}' ] for cmd in commands: try: run_command(cmd) except Exception: exceptions = { 'ncks': NcksError, 'ncpdq': NcpdqError, 'ncatted': NcattedError } cmd_name = cmd.split()[0] raise exceptions[cmd_name](type(self).__name__, self.filename, cmd, traceback.format_exc()) os.remove(bnds_file) os.remove(corrected_bnds_file)
def _run_command(self, cmd, cmd_error): """ Run `cmd` and raise `cmd_error` if it fails when the specified temporary files are deleted. :param str cmd: The command to run :param PreProcError cmd_error: The exception to raise if the command fails """ try: run_command(cmd) except Exception: for fn in self.intermediate_files: if os.path.exists(fn): os.remove(fn) raise cmd_error( type(self).__name__, self.filename, cmd, traceback.format_exc())
def _run_nco_command(self, command_error): """ Run the nco command """ output_file = os.path.join(self.directory, self.filename) temp_file = output_file + '.temp' # Remove any temporary file left over from a previous failed # run as it could prevent some nco commands from running. if os.path.exists(temp_file): os.remove(temp_file) cmd = f'{self.command} {output_file} {temp_file}' try: run_command(cmd) except Exception: if os.path.exists(temp_file): os.remove(temp_file) raise command_error( type(self).__name__, self.filename, cmd, traceback.format_exc()) os.remove(output_file) os.rename(temp_file, output_file)