def test_execute_hourly_without_sun(self): # Prepare input files, without solar radiation self.timestamp = dt.datetime(2014, 10, 1, 15, 0, tzinfo=senegal_tzinfo) self.setup_input_file("temperature", np.array([[38.0, 28.0]])) self.setup_input_file("humidity", np.array([[52.0, 42.0]])) self.setup_input_file("wind_speed", np.array([[3.3, 2.3]])) self.setup_input_file("pressure", np.array([[1013.0, 1013.0]])) # Configuration with open(self.config_file, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} albedo = 0.23 nighttime_solar_radiation_ratio = 0.8 elevation = 8 time_step = H unit_converter_pressure = x / 10.0 unit_converter_solar_radiation = x * 3600 / 1e6 """).format(self=self)) # Execute and check exception msg = "Neither sunshine_duration nor solar_radiation are available" with self.assertRaisesRegex(click.ClickException, msg): cli.App(self.config_file).run()
def test_daily(self): self.setup_daily_input_files() self.setup_config_file("D") # Verify the output file doesn't exist yet result_filename = os.path.join(self.tempdir, "evaporation.hts") assert not os.path.exists(result_filename) # Execute cli.App(self.config_file).run() # Check that it has created a file and that the file is correct with open(result_filename) as f: t = HTimeseries(f) expected_result = pd.DataFrame( data={ "value": [3.9], "flags": [""] }, columns=["value", "flags"], index=[dt.datetime(2014, 7, 6)], ) expected_result.index.name = "date" pd.testing.assert_frame_equal(t.data, expected_result, check_less_precise=1)
def test_missing_altitude(self): self.setup_hourly_input_files(missing="altitude") self.setup_config_file("H") msg = ( "Incorrect or unspecified or inconsistent altitudes in the time series " "files.") with self.assertRaisesRegex(click.ClickException, msg): cli.App(self.config_file).run()
def test_execute_with_dem(self): """This is essentially the same as test_execute, but uses a GeoTIFF with a DEM instead of a constant elevation. The numbers are the same, however (all DEM gridpoints have the same value).""" # Prepare input files self.timestamp = dt.datetime(2014, 10, 1, 15, 0, tzinfo=senegal_tzinfo) self.setup_input_file("temperature", np.array([[38.0, 28.0]])) self.setup_input_file("humidity", np.array([[52.0, 42.0]])) self.setup_input_file("wind_speed", np.array([[3.3, 2.3]])) self.setup_input_file("pressure", np.array([[1013.0, 1013.0]])) self.setup_input_file("solar_radiation", np.array([[681.0, 403.0]])) self.setup_input_file("dem", np.array([[8.0, 8.0]]), with_date=False) with open(self.config_file, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} albedo = 0.23 nighttime_solar_radiation_ratio = 0.8 elevation = dem.tif time_step = H unit_converter_pressure = x / 10.0 unit_converter_solar_radiation = x * 3600 / 1e6 """).format(self=self)) # Verify the output file doesn't exist yet result_filename = os.path.join( self.tempdir, "evaporation-{}.tif".format( self.timestamp.strftime("%Y-%m-%d-%H-%M%z")), ) self.assertFalse(os.path.exists(result_filename)) # Execute cli.App(self.config_file).run() # Check that it has created a file self.assertTrue(os.path.exists(result_filename)) # Check that the created file is correct fp = gdal.Open(result_filename) timestamp = fp.GetMetadata()["TIMESTAMP"] self.assertEqual(timestamp, "2014-10-01T15:00:00-01:00") self.assertEqual(fp.RasterXSize, 2) self.assertEqual(fp.RasterYSize, 1) self.assertEqual(fp.GetGeoTransform(), self.geo_transform) # We can't just compare fp.GetProjection() to self.wgs84.ExportToWkt(), # because sometimes there are minor differences in the formatting or in # the information contained in the WKT. self.assertTrue(fp.GetProjection().startswith('GEOGCS["WGS 84",')) self.assertTrue( fp.GetProjection().endswith('AUTHORITY["EPSG","4326"]]')) np.testing.assert_almost_equal(fp.GetRasterBand(1).ReadAsArray(), np.array([[0.63, 0.36]]), decimal=2) fp = None
def test_albedo_configuration_as_one_number(self, m): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} time_step = H albedo = 0.23 nighttime_solar_radiation_ratio = 0.8 """).format(self=self)) cli.App(self.configfilename).run() m.return_value.execute.assert_called_once_with()
def test_missing_albedo_raises_error(self): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} nighttime_solar_radiation_ratio = 0.8 elevation = 8 time_step = H """).format(self=self)) with self.assertRaisesRegex(click.ClickException, "albedo"): cli.App(self.configfilename).run()
def test_executes(self, m): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} albedo = 0.23 nighttime_solar_radiation_ratio = 0.8 time_step = H unit_converter_pressure = x / 10.0 unit_converter_solar_radiation = x * 3600 /1e6 """).format(self=self)) cli.App(self.configfilename).run() m.return_value.execute.assert_called_once_with()
def test_single_albedo_with_wrong_domain_float_inputs(self): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} time_step = H albedo = 2 nighttime_solar_radiation_ratio = 0.8 elevation = 8 """).format(self=self)) with self.assertRaisesRegex(ValueError, "Albedo must be between 0.0 and 1.0"): cli.App(self.configfilename).run()
def test_run_app_with_seasonal_albedo_with_mix_sample_inputs(self, m): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} time_step = H albedo = a00.tif 0.23 a00.tif a00.tif a00.tif a00.tif a00.tif a00.tif 0.23 a00.tif 0.23 a00.tif nighttime_solar_radiation_ratio = 0.8 elevation = 8 """).format(self=self)) cli.App(self.configfilename).run() m.return_value.execute.assert_called_once_with()
def test_seasonal_albedo_configuration_as_mix_numbers_and_grids(self, m): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} time_step = H albedo = 0.23 a02.tif a03.tif a04.tif a05.tif a06.tif a07.tif a08.tif a09.tif a10.tif a11.tif a12.tif nighttime_solar_radiation_ratio = 0.8 elevation = 8 """).format(self=self)) cli.App(self.configfilename).run() m.return_value.execute.assert_called_once_with()
def test_seasonal_albedo_configuration_with_not_enough_arguments(self): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} time_step = H albedo = a01.tiff a02.tiff a11.tiff a12.tiff nighttime_solar_radiation_ratio = 0.8 elevation = 8 """).format(self=self)) msg = "Albedo must be either one item or 12 space-separated items" with self.assertRaisesRegex(ValueError, msg): cli.App(self.configfilename).run()
def test_seasonal_albedo_configuration_as_12_numbers(self, m): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} time_step = H albedo = 0.10 0.23 0.34 0.24 0.45 0.46 0.34 0.12 0.14 0.78 0.78 0.12 nighttime_solar_radiation_ratio = 0.8 elevation = 8 """).format(self=self)) cli.App(self.configfilename).run() m.return_value.execute.assert_called_once_with()
def test_nonexistent_log_level_raises_error(self): with open(self.configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} albedo = 0.23 nighttime_solar_radiation_ratio = 0.8 elevation = 8 time_step = H unit_converter_pressure = x / 10.0 unit_converter_solar_radiation = x * 3600 /1e6 loglevel = NONEXISTENT_LOG_LEVEL """.format(self=self))) msg = "loglevel must be one of ERROR, WARNING, INFO, DEBUG" with self.assertRaisesRegex(click.ClickException, msg): cli.App(self.configfilename).run()
def test_creates_log_file(self, *args): with tempfile.TemporaryDirectory() as dirname: configfilename = os.path.join(dirname, "evaporation.conf") logfilename = os.path.join(dirname, "vaporize.log") with open(configfilename, "w") as f: f.write( textwrap.dedent("""\ base_dir = {} albedo = 0.23 nighttime_solar_radiation_ratio = 0.8 time_step = H unit_converter_pressure = x / 10.0 unit_converter_solar_radiation = x * 3600 /1e6 logfile = {} """).format(dirname, logfilename)) htsfilename = os.path.join(dirname, "somefile.hts") Path(htsfilename).touch() cli.App(configfilename).run() self.assertTrue(os.path.exists(logfilename))
def test_execute_notz(self): # Prepare input files without time zone self.timestamp = dt.datetime(2014, 10, 1, 15, 0) self.setup_input_file("temperature-notz", np.array([[38.0, 28.0]])) self.setup_input_file("humidity-notz", np.array([[52.0, 42.0]])) self.setup_input_file("wind_speed-notz", np.array([[3.3, 2.3]])) self.setup_input_file("pressure-notz", np.array([[1013.0, 1013.0]])) self.setup_input_file("solar_radiation-notz", np.array([[681.0, 403.0]])) with open(self.config_file, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} albedo = 0.23 nighttime_solar_radiation_ratio = 0.8 elevation = 8 time_step = H unit_converter_pressure = x / 10.0 unit_converter_solar_radiation = x * 3600 / 1e6 temperature_prefix = temperature-notz humidity_prefix = humidity-notz wind_speed_prefix = wind_speed-notz solar_radiation_prefix = solar_radiation-notz pressure_prefix = pressure-notz """).format(self=self)) # Verify the output file doesn't exist yet result_filename = os.path.join( self.tempdir, "evaporation-{}.tif".format( self.timestamp.strftime("%Y-%m-%d-%H-%M%z")), ) self.assertFalse(os.path.exists(result_filename)) # Execute with self.assertRaisesRegex(Exception, "time zone"): cli.App(self.config_file).run() # Verify the output file still doesn't exist self.assertFalse(os.path.exists(result_filename))
def test_execute_hourly_no_pressure(self): """Same as test_execute_hourly, but does not have pressure an input; therefore, it will calculate pressure itself.""" # Prepare input files self.timestamp = dt.datetime(2014, 10, 1, 15, 0, tzinfo=senegal_tzinfo) self.setup_input_file("temperature", np.array([[38.0, 28.0]])) self.setup_input_file("humidity", np.array([[52.0, 42.0]])) self.setup_input_file("wind_speed", np.array([[3.3, 2.3]])) self.setup_input_file("solar_radiation", np.array([[681.0, 403.0]])) # Also setup an output file that has no corresponding input files rogue_output_file = os.path.join( self.tempdir, "evaporation-2013-01-01-15-00-0100.tif") with open(rogue_output_file, "w") as f: f.write("irrelevant contents") with open(self.config_file, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} albedo = 0.23 nighttime_solar_radiation_ratio = 0.8 elevation = 8 time_step = H unit_converter_solar_radiation = x * 3600 / 1e6 """).format(self=self)) # Verify the output file doesn't exist yet result_filename = os.path.join( self.tempdir, "evaporation-{}.tif".format( self.timestamp.strftime("%Y-%m-%d-%H-%M%z")), ) self.assertFalse(os.path.exists(result_filename)) # Verify the rogue output file is still here self.assertTrue(os.path.exists(rogue_output_file)) # Execute cli.App(self.config_file).run() # Check that it has created a file self.assertTrue(os.path.exists(result_filename)) # Check that the rogue output file is gone self.assertFalse(os.path.exists(rogue_output_file)) # Check that the created file is correct fp = gdal.Open(result_filename) timestamp = fp.GetMetadata()["TIMESTAMP"] self.assertEqual(timestamp, "2014-10-01T15:00:00-01:00") self.assertEqual(fp.RasterXSize, 2) self.assertEqual(fp.RasterYSize, 1) self.assertEqual(fp.GetGeoTransform(), self.geo_transform) # We can't just compare fp.GetProjection() to self.wgs84.ExportToWkt(), # because sometimes there are minor differences in the formatting or in # the information contained in the WKT. self.assertTrue(fp.GetProjection().startswith('GEOGCS["WGS 84",')) self.assertTrue( fp.GetProjection().endswith('AUTHORITY["EPSG","4326"]]')) np.testing.assert_almost_equal(fp.GetRasterBand(1).ReadAsArray(), np.array([[0.63, 0.36]]), decimal=2) fp = None
def test_execute_daily_with_radiation(self): """Same as test_execute_daily, except that we use solar radiation instead of sunshine duration.""" # Prepare input files self.timestamp = dt.date(2014, 7, 6) self.setup_input_file("temperature_max", np.array([[21.5, 28]])) self.setup_input_file("temperature_min", np.array([[12.3, 15]])) self.setup_input_file("humidity_max", np.array([[84.0, 70.0]])) self.setup_input_file("humidity_min", np.array([[63.0, 60.0]])) self.setup_input_file("wind_speed", np.array([[2.078, 2.244]])) self.setup_input_file("solar_radiation", np.array([[22.07, 21.62]])) # Also setup an output file that has no corresponding input files rogue_output_file = os.path.join(self.tempdir, "evaporation-2013-01-01.tif") with open(rogue_output_file, "w") as f: f.write("irrelevant contents") with open(self.config_file, "w") as f: f.write( textwrap.dedent("""\ base_dir = {self.tempdir} albedo = 0.23 elevation = 100 time_step = D """).format(self=self)) # Verify the output file doesn't exist yet result_filename = os.path.join( self.tempdir, "evaporation-{}.tif".format(self.timestamp.strftime("%Y-%m-%d")), ) self.assertFalse(os.path.exists(result_filename)) # Verify the rogue output file is still here self.assertTrue(os.path.exists(rogue_output_file)) # Execute cli.App(self.config_file).run() # Check that it has created a file self.assertTrue(os.path.exists(result_filename)) # Check that the rogue output file is gone self.assertFalse(os.path.exists(rogue_output_file)) # Check that the created file is correct fp = gdal.Open(result_filename) timestamp = fp.GetMetadata()["TIMESTAMP"] self.assertEqual(timestamp, "2014-07-06") self.assertEqual(fp.RasterXSize, 2) self.assertEqual(fp.RasterYSize, 1) self.assertEqual(fp.GetGeoTransform(), self.geo_transform) # We can't just compare fp.GetProjection() to self.wgs84.ExportToWkt(), # because sometimes there are minor differences in the formatting or in # the information contained in the WKT. self.assertTrue(fp.GetProjection().startswith('GEOGCS["WGS 84",')) self.assertTrue( fp.GetProjection().endswith('AUTHORITY["EPSG","4326"]]')) np.testing.assert_almost_equal(fp.GetRasterBand(1).ReadAsArray(), np.array([[3.9, 4.8]]), decimal=1) fp = None