diff --git a/VERSION b/VERSION index 18091983f59ddde8105e566545a0d9e4a12a4f1c..1545d966571dc86b54c98f888a0e6451501f8c81 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -3.4.0 +3.5.0 diff --git a/doc/source/codedoc/ocean.rst b/doc/source/codedoc/ocean.rst index 52830bb9ccdc0e114c4506ed1f9d836aeda99834..acf9ad14cf9d6bbe7f6d4b62d18093bc69da3eac 100644 --- a/doc/source/codedoc/ocean.rst +++ b/doc/source/codedoc/ocean.rst @@ -25,6 +25,12 @@ earthdiagnostics.ocean.cutsection :show-inheritance: :members: +earthdiagnostics.ocean.density +------------------------------ +.. automodule:: earthdiagnostics.ocean.density + :show-inheritance: + :members: + earthdiagnostics.ocean.gyres ---------------------------- .. automodule:: earthdiagnostics.ocean.gyres diff --git a/doc/source/conf.py b/doc/source/conf.py index 1501231f416a1f239ec0751614c114c9442fb4bc..17ef04e572063310657798260ad3b7e2e86cb4be 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -63,9 +63,9 @@ copyright = u"2020, BSC-CNS Earth Sciences Department" # built documents.source ~/vi # # The short X.Y version. -version = "3.4" +version = "3.5" # The full version, including alpha/beta/rc tags. -release = "3.4.0" +release = "3.5.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/diagnostic_list.rst b/doc/source/diagnostic_list.rst index de450a4f55f7b23e2695e6e1b91409d2452ade91..f95ab6afd905ca62f6e3fbc3bd4d8c67fed25b62 100644 --- a/doc/source/diagnostic_list.rst +++ b/doc/source/diagnostic_list.rst @@ -315,6 +315,16 @@ Options: 4. Domain = ocean: Variable's domain +density +~~~~~~~ + +Compute the total potential density anomaly. See :class:`~earthdiagnostics.ocean.density.Density` + +Options: +******** + +This diagnostic has no options + gyres ~~~~~ @@ -356,14 +366,14 @@ See :class:`~earthdiagnostics.ocean.heatcontentlayer.HeatContentLayer` Options: ******** -3. Min depth: +1. Min depth: Minimum depth for the calculation in meteres -4. Max depth: +2. Max depth: Maximum depth for the calculation in meters -5. Basin = 'Global': - Basin to calculate the heat content on. +3. Basins = ['Global']: + List of basins to calculate the heat content on. interpolate ~~~~~~~~~~~ @@ -381,8 +391,8 @@ Options: 1. Target grid: New grid for the data -2. Variable: - Variable to interpolate +2. VariableList: + List of variables to interpolate 3. Domain = ocean: Variable's domain diff --git a/docker/dockerfile b/docker/dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..f1fec2ad49fd98439944d6293f82babfae990c72 --- /dev/null +++ b/docker/dockerfile @@ -0,0 +1,15 @@ +#FROM continuumio/miniconda3:jessie-20190506 +FROM bsces/miniconda3:debian-stretch-20190610 + +COPY . /src/earthdiagnostics +WORKDIR /src +RUN git clone https://earth.bsc.es/gitlab/es/diagonals.git +RUN conda update -y conda pip && conda env update --name base --file earthdiagnostics/environment.yml && conda clean --all -y +RUN pip install ./diagonals ./earthdiagnostics && pip cache purge +RUN rm -r /src + +# run tests +RUN earthdiags -h + +ENTRYPOINT ["earthdiags"] +CMD ["-h"] diff --git a/earthdiagnostics/config.py b/earthdiagnostics/config.py index 7340daddb28c84f093cf149a883f914f746117df..8d373efa612afe292d139063b6caaaa9c6b05310 100644 --- a/earthdiagnostics/config.py +++ b/earthdiagnostics/config.py @@ -238,7 +238,8 @@ class Config(object): " ".join(added_commands), ) for add_command in added_commands: - self._real_commands.append(add_command) + if add_command: + self._real_commands.append(add_command) else: self._real_commands.append(command) diff --git a/earthdiagnostics/data_convention.py b/earthdiagnostics/data_convention.py index eb137782b01ff5a9be15ca5a95173381258a411b..5e4dd4b5a96d8ce236f70485a6e7e36556a32df7 100644 --- a/earthdiagnostics/data_convention.py +++ b/earthdiagnostics/data_convention.py @@ -812,8 +812,16 @@ class Cmor3Convention(DataConvention): "month", self.config.experiment.calendar, ) - - if frequency == Frequencies.monthly: + if frequency == Frequencies.yearly: + chunk_end = previous_day( + chunk_end, self.config.experiment.calendar + ) + time_bound = "{0:04}{2}{1:04}".format( + chunk_start.year, + chunk_end.year, + self.time_separator, + ) + elif frequency == Frequencies.monthly: chunk_end = previous_day( chunk_end, self.config.experiment.calendar ) @@ -884,10 +892,15 @@ class Cmor3Convention(DataConvention): self.config.cmor.version, ) if self.config.cmor.version == "latest": - versions = os.listdir(os.path.dirname(folder_path)) + base_path = os.path.dirname(folder_path) + if not os.path.isdir(base_path): + base_path = base_path.replace( + '/original_files/cmorfiles/', '/cmorfiles/') + versions = os.listdir(base_path) versions.sort(reverse=True) self.config.cmor.version = versions[0] - folder_path = folder_path.replace('/latest/', f'/{versions[0]}/') + return self.get_cmor_folder_path( + startdate, member, domain, var, frequency, grid, cmor_var) return folder_path diff --git a/earthdiagnostics/datafile.py b/earthdiagnostics/datafile.py index 1390a97345b9ab444f6f92ee39113290a581ffe5..54a0c4b109fa5b35a4f938c7f5ebc411c1b9449e 100644 --- a/earthdiagnostics/datafile.py +++ b/earthdiagnostics/datafile.py @@ -474,6 +474,7 @@ class DataFile(Publisher): if len(cube_list) == 1: return iris.experimental.equalise_cubes.equalise_attributes(cube_list) + iris.util.unify_time_units(cube_list) final_cube = cube_list.merge_cube() temp = TempFile.get() iris.save(final_cube, temp, zlib=True) diff --git a/earthdiagnostics/earthdiags.py b/earthdiagnostics/earthdiags.py index dfcba88a5534dd7cd7f977ba85f800917b5a5b38..adda458001d1bd0af7f376a999f19f7deeb1ab01 100755 --- a/earthdiagnostics/earthdiags.py +++ b/earthdiagnostics/earthdiags.py @@ -514,7 +514,7 @@ class EarthDiags(object): Log.info("File {0} already exists", destiny) return True - Log.info("Copying file {0}", destiny) + Log.info("Copying file {0}", os.path.abspath(destiny)) shutil.copyfile(source, destiny) Log.info("File {0} ready", destiny) Utils.rename_variables(destiny, self.dic_variables, False) diff --git a/earthdiagnostics/ocean/density.py b/earthdiagnostics/ocean/density.py new file mode 100644 index 0000000000000000000000000000000000000000..d4d4aea489c0ef4916727764385fc1ce29f0829f --- /dev/null +++ b/earthdiagnostics/ocean/density.py @@ -0,0 +1,150 @@ +# coding=utf-8 +"""Compute the potential density anomalies""" +import diagonals.density +import numpy as np +import iris + +from earthdiagnostics.modelingrealm import ModelingRealms +from earthdiagnostics.utils import TempFile +from earthdiagnostics.diagnostic import Diagnostic + + +class Density(Diagnostic): + """ + Compute the total potential density anomaly + + + :param data_manager: data management object + :type data_manager: DataManager + :param startdate: startdate + :type startdate: str + :param member: member number + :type member: int + :param chunk: chunk's number + :type chunk: int + """ + + alias = "density" + "Diagnostic alias for the configuration file" + + def __init__( + self, + data_manager, + startdate, + member, + chunk, + ): + Diagnostic.__init__(self, data_manager) + self.startdate = startdate + self.member = member + self.chunk = chunk + self.sigmas = [0, 2] + + def __eq__(self, other): + if self._different_type(other): + return False + return ( + self.startdate == other.startdate + and self.member == other.member + and self.chunk == other.chunk + ) + + def __str__(self): + return ( + f"Density Startdate: {self.startdate} Member: {self.member} " + f"Chunk: {self.chunk}" + ) + + def __hash__(self): + return hash(str(self)) + + @classmethod + def generate_jobs(cls, diags, options): + """ + Create a job for each chunk to compute the diagnostic + + :param diags: Diagnostics manager class + :type diags: Diags + :param options: This diagnostic does not require extra options + :type options: list[str] + :return: + """ + options_available = [] + options = cls.process_options(options, options_available) + + job_list = list() + for ( + startdate, + member, + chunk, + ) in diags.config.experiment.get_chunk_list(): + job_list.append( + Density( + diags.data_manager, + startdate, + member, + chunk, + ) + ) + return job_list + + def request_data(self): + """Request data required by the diagnostic""" + self.bigthetao = self.request_chunk( + ModelingRealms.ocean, + "bigthetao", + self.startdate, + self.member, + self.chunk, + ) + self.so = self.request_chunk( + ModelingRealms.ocean, + "so", + self.startdate, + self.member, + self.chunk, + ) + + def declare_data_generated(self): + """Declare data to be generated by the diagnostic""" + self.sigma = {} + for sigma in self.sigmas: + self.sigma[sigma] = self.declare_chunk( + ModelingRealms.ocean, + f"sigma{sigma}", + self.startdate, + self.member, + self.chunk, + ) + + def compute(self): + """Run the diagnostic""" + bigthetao = iris.load_cube(self.bigthetao.local_file) + so = iris.load_cube(self.so.local_file) + # Convert from practical to absolute + so = so / 0.99530670233846 + + for sigma in self.sigmas: + ref_pressure = sigma * 1000 + sigma_values = [] + for time in range(so.shape[0]): + sigma_values.append(diagonals.density.compute( + so[time, ...].data.astype(np.float32), + bigthetao.data[time, ...].astype(np.float32), + np.full(bigthetao.shape[1:], + ref_pressure, dtype=np.float32) + )) + sigma_values = np.stack(sigma_values) + sigma_cube = bigthetao.copy(sigma_values) + sigma_cube.var_name = f'sigma{sigma}' + sigma_cube.standard_name = 'sea_water_sigma_theta' + sigma_cube.long_name = ( + "potential density anomaly (potential density minus 1000 " + f"Kg/m3) with reference pressure of {ref_pressure} dbar" + ) + sigma_cube.units = 'kg m-3' + temp = TempFile.get() + iris.save(sigma_cube, temp, zlib=True) + del sigma_cube + del sigma_values + self.sigma[sigma].set_local_file(temp) diff --git a/earthdiagnostics/ocean/interpolatecdo.py b/earthdiagnostics/ocean/interpolatecdo.py index dd514e1d84a18c304d513ea7a1308fc7c0582a28..3de0f28ac58d00a67b402fab8e73d0ec174d5d90 100644 --- a/earthdiagnostics/ocean/interpolatecdo.py +++ b/earthdiagnostics/ocean/interpolatecdo.py @@ -12,6 +12,7 @@ from earthdiagnostics.diagnostic import ( DiagnosticChoiceOption, DiagnosticBoolOption, DiagnosticOption, + DiagnosticFrequencyOption, ) from earthdiagnostics.modelingrealm import ModelingRealms from earthdiagnostics.utils import Utils, TempFile @@ -66,6 +67,7 @@ class InterpolateCDO(Diagnostic): mask_oceans, original_grid, weights, + frequency, ): Diagnostic.__init__(self, data_manager) self.startdate = startdate @@ -81,6 +83,7 @@ class InterpolateCDO(Diagnostic): self.mask_oceans = mask_oceans self.original_grid = original_grid self.weights = weights + self.frequency = frequency def __eq__(self, other): if self._different_type(other): @@ -96,6 +99,7 @@ class InterpolateCDO(Diagnostic): and self.mask_oceans == other.mask_oceans and self.grid == other.grid and self.original_grid == other.original_grid + and self.frequency == other.frequency ) def __hash__(self): @@ -105,6 +109,7 @@ class InterpolateCDO(Diagnostic): return ( "Interpolate with CDO Startdate: {0.startdate} Member: {0.member} " "Chunk: {0.chunk} Variable: {0.domain}:{0.variable} " + "Frequency: {0.frequency} " "Target grid: {0.grid} Original grid: {0.original_grid} " "Mask ocean: {0.mask_oceans} Model: {0.model_version}".format(self) ) @@ -134,6 +139,8 @@ class InterpolateCDO(Diagnostic): DiagnosticBoolOption("mask_oceans", True), DiagnosticOption("original_grid", ""), DiagnosticBoolOption("weights_from_mask", True), + DiagnosticFrequencyOption( + default_value=diags.config.frequency), ) options = cls.process_options(options, options_available) target_grid = cls._translate_ifs_grids_to_cdo_names( @@ -166,6 +173,7 @@ class InterpolateCDO(Diagnostic): options["original_grid"], weights, options["method"], + options["frequency"], ) for var in options["variables"]: @@ -186,6 +194,7 @@ class InterpolateCDO(Diagnostic): options["mask_oceans"], options["original_grid"], weights, + options["frequency"] ) if weights_job is not None: job.add_subjob(weights_job) @@ -326,6 +335,7 @@ class InterpolateCDO(Diagnostic): self.member, self.chunk, grid=self.original_grid, + frequency=self.frequency, ) def declare_data_generated(self): @@ -337,6 +347,7 @@ class InterpolateCDO(Diagnostic): self.member, self.chunk, grid=self.grid, + frequency=self.frequency, ) def compute(self): @@ -451,6 +462,7 @@ class ComputeWeights(Diagnostic): original_grid, weights_file, method, + frequency ): Diagnostic.__init__(self, data_manager) self.startdate = startdate @@ -462,6 +474,7 @@ class ComputeWeights(Diagnostic): self.original_grid = original_grid self.weights_file = weights_file self.method = method + self.frequency = frequency def __str__(self): return ( @@ -487,6 +500,7 @@ class ComputeWeights(Diagnostic): self.member, self.chunk, grid=self.original_grid, + frequency=self.frequency, ) def declare_data_generated(self): diff --git a/earthdiagnostics/ocean/moc.py b/earthdiagnostics/ocean/moc.py index f5931fc8b622bb7a0d9c40007cd8ecfe18ef91f3..4f3f3c5dd5789659b162214d1c1f26bda0037b67 100644 --- a/earthdiagnostics/ocean/moc.py +++ b/earthdiagnostics/ocean/moc.py @@ -45,6 +45,7 @@ class Moc(Diagnostic): def __init__(self, data_manager, startdate, member, chunk, basins): Diagnostic.__init__(self, data_manager) + self.data_convention = data_manager.convention self.startdate = startdate self.member = member self.chunk = chunk @@ -161,21 +162,25 @@ class Moc(Diagnostic): "region", "S1", ("region", "region_length") ) - lat = handler_temp.createVariable("lat", float, ("j", "i")) + lat = handler_temp.createVariable( + self.data_convention.lat_name, float, ("j", "i")) lat[...] = gphiv[:, max_gphiv] lat.units = "degrees_north" lat.long_name = "Latitude" + lat.standard_name = "latitude" - lon = handler_temp.createVariable("lon", float, ("j", "i")) + lon = handler_temp.createVariable( + self.data_convention.lon_name, float, ("j", "i")) lon[...] = 0 lon.units = "degrees_east" lon.long_name = "Longitude" + lon.standard_name = "longitude" var = handler_temp.createVariable( "vsftmyz", float, ("time", "lev", "i", "j", "region") ) var.units = "Sverdrup" - var.coordinates = "lev time" + var.coordinates = "lev time latitude longitude" var.long_name = "Ocean meridional overturning volume streamfunction" var.missing_value = 1e20 var.fill_value = 1e20 diff --git a/earthdiagnostics/ocean/regionmean.py b/earthdiagnostics/ocean/regionmean.py index fe9cc8131246e3d531f5edd01a69c4814f8e293f..b1a48300defc7f6ba029cbe076a45d29436c81bd 100644 --- a/earthdiagnostics/ocean/regionmean.py +++ b/earthdiagnostics/ocean/regionmean.py @@ -253,25 +253,25 @@ class RegionMean(Diagnostic): return cube def _load_data(self): - coords = [] - handler = Utils.open_cdf(self.variable_file.local_file) - for variable in handler.variables: - if variable in ( - "time", - "lev", - "lat", - "lon", - "latitude", - "longitude", - "leadtime", - "time_centered", - ): - coords.append(variable) - if variable == "time_centered": - handler.variables[variable].standard_name = "" - - handler.variables[self.variable].coordinates = " ".join(coords) - handler.close() + # handler = Utils.open_cdf(self.variable_file.local_file) + # coords = set(handler.variables[self.variable].coordinates.split(' ')) + # for variable in handler.variables: + # if variable in ( + # "time", + # "lev", + # "lat", + # "lon", + # "latitude", + # "longitude", + # "leadtime", + # "time_centered", + # ): + # coords.add(variable) + # if variable == "time_centered": + # handler.variables[variable].standard_name = "" + + # handler.variables[self.variable].coordinates = " ".join(coords) + # handler.close() data = iris.load_cube(self.variable_file.local_file) return self._rename_depth(data) @@ -287,24 +287,10 @@ class RegionMean(Diagnostic): def _fix_file_metadata(self): handler = Utils.open_cdf(self.variable_file.local_file) - var = handler.variables[self.variable] - coordinates = "" has_levels = False for dimension in handler.variables.keys(): - if dimension in [ - "time", - "lev", - "lat", - "latitude", - "lon", - "longitude", - "i", - "j", - ]: - coordinates += " {0}".format(dimension) if dimension == "lev": has_levels = True - var.coordinates = coordinates handler.close() return has_levels diff --git a/earthdiagnostics/work_manager.py b/earthdiagnostics/work_manager.py index 3666e2c791b58b5f3f5251718b23a79da0910458..9192b58c07464a80afe8f3c1c1eb86f7a7e76cca 100644 --- a/earthdiagnostics/work_manager.py +++ b/earthdiagnostics/work_manager.py @@ -407,6 +407,7 @@ class WorkManager(object): from .ocean.sivolume import Sivolume from .ocean.sivol2d import Sivol2d from .ocean.zonalmean import ZonalMean + from .ocean.density import Density Diagnostic.register(MixedLayerSaltContent) Diagnostic.register(Siasiesiv) @@ -433,6 +434,7 @@ class WorkManager(object): Diagnostic.register(Sivolume) Diagnostic.register(Sivol2d) Diagnostic.register(ZonalMean) + Diagnostic.register(Density) class Downloader(object): diff --git a/environment.yml b/environment.yml index 5b9fe6a605a81500f32b6e1b92e9b59e47976c56..f6657b17536641cd918ae39457b0db3f353df7b2 100644 --- a/environment.yml +++ b/environment.yml @@ -5,10 +5,9 @@ channels: - conda-forge dependencies: -- netcdf4 -- numpy +- python=3.7.4 - cdo - nco - eccodes - six -- iris>=2.2 +- iris>=2.4 diff --git a/setup.py b/setup.py index f4571a319913c9d946200bd3bb8344714a42f65e..4fab770a8127a3f8437d6a259d328342f48ac23f 100644 --- a/setup.py +++ b/setup.py @@ -24,14 +24,14 @@ REQUIREMENTS = { "cdo>=1.3.4", "cfgrib", "dask[array]", - "diagonals", + "diagonals>=0.3", "netCDF4", "nco>=0.0.3", "numba", "numpy", "psutil", "openpyxl", - "scitools-iris>=2.2", + "scitools-iris>=2.4", "six", "xxhash", ], diff --git a/test/unit/ocean/test_density.py b/test/unit/ocean/test_density.py new file mode 100644 index 0000000000000000000000000000000000000000..92b4e06db3fd089ce3168511d72c5fa12c9b4efc --- /dev/null +++ b/test/unit/ocean/test_density.py @@ -0,0 +1,42 @@ +# coding=utf-8 +from unittest import TestCase + +from mock import Mock + +from earthdiagnostics.ocean.density import Density + + +class TestHeatContent(TestCase): + def setUp(self): + self.data_manager = Mock() + + self.diags = Mock() + self.diags.model_version = "model_version" + self.diags.config.experiment.get_chunk_list.return_value = ( + ("20010101", 0, 0), + ("20010101", 0, 1), + ) + + def test_generate_jobs(self): + jobs = Density.generate_jobs( + self.diags, ["diagnostic"] + ) + self.assertEqual(len(jobs), 2) + self.assertEqual( + jobs[0], + Density(self.data_manager, "20010101", 0, 0) + ) + self.assertEqual( + jobs[1], + Density(self.data_manager, "20010101", 0, 1) + ) + + with self.assertRaises(Exception): + Density.generate_jobs(self.diags, ["diagnostic", "0"]) + + def test_str(self): + diag = Density(self.data_manager, "20010101", 0, 0) + self.assertEqual( + str(diag), + "Density Startdate: 20010101 Member: 0 Chunk: 0" + ) diff --git a/test/unit/ocean/test_interpolatecdo.py b/test/unit/ocean/test_interpolatecdo.py index cc2d86ae7c20e771114183afa337c8d6ddce06b4..5b546dd93d4abb1d3a4c5199343b507983f82976 100644 --- a/test/unit/ocean/test_interpolatecdo.py +++ b/test/unit/ocean/test_interpolatecdo.py @@ -5,6 +5,7 @@ from earthdiagnostics.ocean.interpolatecdo import InterpolateCDO from mock import Mock, patch from earthdiagnostics.modelingrealm import ModelingRealms +from earthdiagnostics.frequency import Frequencies from earthdiagnostics.diagnostic import ( DiagnosticVariableListOption, DiagnosticOptionError, @@ -23,6 +24,7 @@ class TestInterpolate(TestCase): ) self.diags.config.experiment.model_version = "model_version" self.diags.config.experiment.atmos_grid = "atmos_grid" + self.diags.config.frequency = Frequencies.daily def fake_parse(self, value): if not value: @@ -63,6 +65,7 @@ class TestInterpolate(TestCase): True, "", None, + Frequencies.daily, ), ) self.assertEqual( @@ -79,6 +82,7 @@ class TestInterpolate(TestCase): True, "", None, + Frequencies.daily, ), ) @@ -100,6 +104,7 @@ class TestInterpolate(TestCase): True, "", None, + Frequencies.daily, ), ) self.assertEqual( @@ -116,6 +121,7 @@ class TestInterpolate(TestCase): True, "", None, + Frequencies.daily, ), ) @@ -137,6 +143,7 @@ class TestInterpolate(TestCase): True, "", None, + Frequencies.daily, ), ) self.assertEqual( @@ -153,6 +160,7 @@ class TestInterpolate(TestCase): True, "", None, + Frequencies.daily, ), ) @@ -175,6 +183,7 @@ class TestInterpolate(TestCase): False, "", None, + Frequencies.daily, ), ) self.assertEqual( @@ -191,6 +200,7 @@ class TestInterpolate(TestCase): False, "", None, + Frequencies.daily, ), ) @@ -221,6 +231,7 @@ class TestInterpolate(TestCase): False, "orig", None, + Frequencies.daily, ), ) self.assertEqual( @@ -237,6 +248,7 @@ class TestInterpolate(TestCase): False, "orig", None, + Frequencies.daily, ), ) @@ -268,6 +280,7 @@ class TestInterpolate(TestCase): False, "orig", None, + Frequencies.daily, ), ) self.assertEqual( @@ -284,6 +297,57 @@ class TestInterpolate(TestCase): False, "orig", None, + Frequencies.daily, + ), + ) + + jobs = InterpolateCDO.generate_jobs( + self.diags, + [ + "interpcdo", + "ocean", + "var", + "target_grid", + "bicubic", + "false", + "orig", + "false", + "mon" + ], + ) + self.assertEqual(len(jobs), 2) + self.assertEqual( + jobs[0], + InterpolateCDO( + self.data_manager, + "20010101", + 0, + 0, + ModelingRealms.ocean, + "var", + "target_grid", + "model_version", + False, + "orig", + None, + Frequencies.monthly, + ), + ) + self.assertEqual( + jobs[1], + InterpolateCDO( + self.data_manager, + "20010101", + 0, + 1, + ModelingRealms.ocean, + "var", + "target_grid", + "model_version", + False, + "orig", + None, + Frequencies.monthly, ), ) @@ -301,6 +365,7 @@ class TestInterpolate(TestCase): "false", "orig", "false", + "daily," "extra", ], ) @@ -318,11 +383,12 @@ class TestInterpolate(TestCase): False, "orig", None, + Frequencies.monthly, ) self.assertEqual( str(diag), "Interpolate with CDO Startdate: 20010101 Member: 0 Chunk: 0 " - "Variable: ocean:var " + "Variable: ocean:var Frequency: mon " "Target grid: atmos_grid Original grid: orig Mask ocean: False " "Model: model_version", ) diff --git a/test/unit/test_config.py b/test/unit/test_config.py index 5e4a1ae658d68feca96adfc1591f9a380c883701..b8bc4cc0f472506ca32ceaaee94164cbff6c2909 100644 --- a/test/unit/test_config.py +++ b/test/unit/test_config.py @@ -745,6 +745,13 @@ class TestConfig(TestCase): self._parse(config) self.assertEqual(config.get_commands(), ["diag3", "diag2"]) + def test_empty_alias(self): + """Test alias parsing""" + config = Config() + self.mock_parser.add_value("ALIAS", "diag1", "") + self._parse(config) + self.assertEqual(config.get_commands(), ["diag2"]) + def test_auto_clean_ram_disk(self): """Test that USE_RAMDISK forces AUTO_CLEAN to true""" config = Config()