diff --git a/pyDeltaRCM/default.yml b/pyDeltaRCM/default.yml index e2f70762..7a5e81f1 100644 --- a/pyDeltaRCM/default.yml +++ b/pyDeltaRCM/default.yml @@ -1,9 +1,3 @@ -site_prefix: - type: 'str' - default: '' -case_prefix: - type: 'str' - default: '' out_dir: type: 'str' default: 'deltaRCM_Output' diff --git a/pyDeltaRCM/deltaRCM_tools.py b/pyDeltaRCM/deltaRCM_tools.py index fc62485f..1a214571 100644 --- a/pyDeltaRCM/deltaRCM_tools.py +++ b/pyDeltaRCM/deltaRCM_tools.py @@ -6,6 +6,7 @@ import string import logging import time +import warnings from math import floor, sqrt, pi import numpy as np @@ -48,6 +49,8 @@ def run_one_timestep(self): timestep = self._time + self.logger.info('-' * 4 + ' Timestep ' + + str(self._time) + ' ' + '-' * 4) if self.verbose > 0: print('-' * 20) print('Timestep: ' + str(self._time)) @@ -55,6 +58,7 @@ def run_one_timestep(self): if self._is_finalized: raise RuntimeError('Cannot update model, model already finalized!') + # model operations for iteration in range(self.itermax): self.init_water_iteration() @@ -101,8 +105,10 @@ def expand_stratigraphy(self): """ - if self.verbose: - self.logger.info('Expanding stratigraphy arrays') + _msg = 'Expanding stratigraphy arrays' + self.logger.info(_msg) + if self.verbose >= 2: + print(_msg) lil_blank = lil_matrix((self.L * self.W, self.n_steps), dtype=np.float32) @@ -143,8 +149,10 @@ def record_stratigraphy(self): if self.strata_eta.shape[1] <= timestep: self.expand_stratigraphy() + _msg = 'Storing stratigraphy data' + self.logger.info(_msg) if self.verbose >= 2: - self.logger.info('Storing stratigraphy data') + print(_msg) # ------------------ sand frac ------------------ # -1 for cells with deposition volumes < vol_limit @@ -211,8 +219,12 @@ def apply_subsidence(self): timestep = self._time if self.start_subsidence <= timestep: + + _msg = 'Applying subsidence' + self.logger.info(_msg) if self.verbose >= 2: - self.logger.info('Applying subsidence') + print(_msg) + self.eta[:] = self.eta - self.sigma def output_data(self): @@ -252,34 +264,34 @@ def output_data(self): plt.clim(self.clim_eta[0], self.clim_eta[1]) plt.colorbar() plt.axis('equal') - self.save_figure(self.prefix + "eta_" + str(timestep)) + self.save_figure(os.path.join(self.prefix, 'eta_' + str(timestep))) if self.save_stage_figs: plt.pcolor(self.stage) plt.colorbar() plt.axis('equal') - self.save_figure(self.prefix + "stage_" + str(timestep)) + self.save_figure(os.path.join(self.prefix, 'stage_' + str(timestep))) if self.save_depth_figs: plt.pcolor(self.depth) plt.colorbar() plt.axis('equal') - self.save_figure(self.prefix + "depth_" + str(timestep)) + self.save_figure(os.path.join(self.prefix, 'depth_' + str(timestep))) if self.save_discharge_figs: plt.pcolor(self.qw) plt.colorbar() plt.axis('equal') - self.save_figure(self.prefix + "discharge_" + str(timestep)) + self.save_figure(os.path.join(self.prefix, 'discharge_' + str(timestep))) if self.save_velocity_figs: plt.pcolor(self.uw) plt.colorbar() plt.axis('equal') - self.save_figure(self.prefix + "velocity_" + str(timestep)) + self.save_figure(os.path.join(self.prefix, 'velocity_' + str(timestep))) # ------------------ grids ------------------ if self.save_eta_grids: @@ -322,15 +334,18 @@ def output_strata(self): if self.save_strata: + _msg = 'Saving final stratigraphy to netCDF file' + self.logger.info(_msg) if self.verbose >= 2: - self.logger.info('\nSaving final stratigraphy to netCDF file') + print(_msg) self.strata_eta = self.strata_eta[:, :self.strata_counter] shape = self.strata_eta.shape if shape[0] < 1: raise RuntimeError('Stratigraphy are empty! ' - 'Are you sure you ran the model with `update()`?') + 'Are you sure you ran the model at least ' + 'one timestep with `update()`?') total_strata_age = self.output_netcdf.createDimension( 'total_strata_age', diff --git a/pyDeltaRCM/init_tools.py b/pyDeltaRCM/init_tools.py index ae35d74e..6bdb4de0 100644 --- a/pyDeltaRCM/init_tools.py +++ b/pyDeltaRCM/init_tools.py @@ -4,7 +4,8 @@ import re import string import logging -import time +# import time +import warnings from math import floor, sqrt, pi import numpy as np @@ -20,7 +21,7 @@ import time as time_lib from scipy.sparse import lil_matrix, csc_matrix, hstack import logging -import time +# import time import yaml from . import shared_tools @@ -30,22 +31,39 @@ class init_tools(object): + def init_output_infrastructure(self): + + # output directory config + self.prefix = self.out_dir + self.prefix_abspath = os.path.abspath(self.prefix) + + # create directory if it does not exist + if not os.path.exists(self.prefix_abspath): + os.makedirs(self.prefix_abspath) + assert os.path.isdir(self.prefix_abspath) # validate dir created + def init_logger(self): + """Initialize a logger. - if self.verbose >= 1: + The logger is initialized regardless of the value of ``self.verbose``. + The level of information printed to the log depends on the verbosity + setting. - self.logger = logging.getLogger("driver") - self.logger.setLevel(logging.INFO) + """ - # create the logging file handler - st = timestr = time.strftime("%Y%m%d-%H%M%S") - fh = logging.FileHandler("pyDeltaRCM_" + st + ".log") - formatter = logging.Formatter( - '%(asctime)s - %(name)s - %(levelname)s - %(message)s') - fh.setFormatter(formatter) + self.logger = logging.getLogger('driver') + self.logger.setLevel(logging.INFO) - # add handler to logger object - self.logger.addHandler(fh) + # create the logging file handler + st = timestr = time_lib.strftime('%Y%m%d-%H%M%S') + fh = logging.FileHandler( + self.prefix_abspath + '/pyDeltaRCM_' + st + '.log') + formatter = logging.Formatter( + '%(asctime)s - %(levelname)s - %(message)s') + fh.setFormatter(formatter) + + # add handler to logger object + self.logger.addHandler(fh) def import_files(self): @@ -97,13 +115,29 @@ def import_files(self): for k, v in list(input_file_vars.items()): setattr(self, k, v) + def determine_random_seed(self): + """Set the random seed if given. + + If a random seed is specified, set the seed to this value. + + Writes the seed to the log for record. + """ if self.seed is not None: + + _msg = 'Setting random seed to: %s ' % str(self.seed) + self.logger.info(_msg) if self.verbose >= 2: - print("setting random seed to %s " % str(self.seed)) + print(_msg) + shared_tools.set_random_seed(self.seed) + # always write the seed to file for record and reproducability + self.logger.info('Random seed is: %s ' % str(self.seed)) + def set_constants(self): + self.logger.info('Setting model constants') + self.g = 9.81 # (gravitation const.) sqrt2 = np.sqrt(2) @@ -217,16 +251,6 @@ def create_other_variables(self): self.diffusion_multiplier = (self.dt / self.N_crossdiff * self.alpha * 0.5 / self.dx**2) - - # output directory config - self.prefix = self.out_dir - - if self.out_dir[-1] != '/': - self.prefix = self.out_dir + '/' - if self.site_prefix: - self.prefix += self.site_prefix + '_' - if self.case_prefix: - self.prefix += self.case_prefix + '_' self._is_finalized = False @@ -235,8 +259,9 @@ def create_domain(self): Creates the model domain """ - # ---- empty arrays ---- + self.logger.info('Creating model domain') + # ---- empty arrays ---- self.x, self.y = np.meshgrid( np.arange(0, self.W), np.arange(0, self.L)) @@ -326,11 +351,11 @@ def init_stratigraphy(self): self.n_steps = 5 * self.save_dt self.strata_sand_frac = lil_matrix((self.L * self.W, self.n_steps), - dtype = np.float32) + dtype=np.float32) self.init_eta = self.eta.copy() self.strata_eta = lil_matrix((self.L * self.W, self.n_steps), - dtype = np.float32) + dtype=np.float32) def init_output_grids(self): """Creates a netCDF file to store output grids. @@ -348,22 +373,20 @@ def init_output_grids(self): self.save_velocity_grids or self.save_strata): + _msg = 'Generating netCDF file for output grids' + self.logger.info(_msg) if self.verbose >= 2: - self.logger.info('Generating netCDF file for output grids...') + print(_msg) directory = self.prefix filename = 'pyDeltaRCM_output.nc' - if not os.path.exists(directory): - if self.verbose >= 2: - self.logger.info('Creating output directory') - os.makedirs(directory) - file_path = os.path.join(directory, filename) - if os.path.exists(file_path): + _msg = 'Replacing existing netCDF file' + self.logger.warning(_msg) if self.verbose >= 2: - self.logger.info('*** Replaced existing netCDF file ***') + warnings.warn(UserWarning(_msg)) os.remove(file_path) self.output_netcdf = Dataset(file_path, 'w', @@ -421,8 +444,10 @@ def init_output_grids(self): ('total_time', 'length', 'width')) velocity.units = 'meters per second' + _msg = 'Output netCDF file created' + self.logger.info(_msg) if self.verbose >= 2: - self.logger.info('Output netCDF file created.') + print(_msg) def init_subsidence(self): """ diff --git a/pyDeltaRCM/model.py b/pyDeltaRCM/model.py index c56c822d..3cd11818 100644 --- a/pyDeltaRCM/model.py +++ b/pyDeltaRCM/model.py @@ -56,16 +56,20 @@ def __init__(self, input_file=None): self.default_file = os.path.join(_src_dir, 'default.yml') self.import_files() - self.create_other_variables() - + self.init_output_infrastructure() self.init_logger() + self.create_other_variables() + + self.determine_random_seed() self.create_domain() self.init_subsidence() self.init_stratigraphy() self.init_output_grids() + self.logger.info('Model initialization complete') + def update(self): """Run the model for one full instance @@ -113,12 +117,16 @@ def finalize(self): """ + self.logger.info('Finalize model run') + self.output_strata() try: self.output_netcdf.close() - if self.verbose >= 1: - print('Closed output netcdf file.') + _msg = 'Closed output netcdf file' + self.logger.info(_msg) + if self.verbose >= 2: + print(_msg) except Exception: pass diff --git a/pyDeltaRCM/water_tools.py b/pyDeltaRCM/water_tools.py index 0add31cf..505bbcaf 100644 --- a/pyDeltaRCM/water_tools.py +++ b/pyDeltaRCM/water_tools.py @@ -194,9 +194,10 @@ def check_size_of_indices_matrix(self, it): Once it reaches it > self.itmax/2 once, make the size self.iter for all further timesteps """ - + _msg = 'Increasing size of self.indices' + self.logger.info(_msg) if self.verbose >= 2: - self.logger.info('Increasing size of self.indices') + print(_msg) indices_blank = np.zeros( (np.int(self.Np_water), np.int(self.itmax / 4)), dtype=np.int) diff --git a/run_pyDeltaRCM.py b/run_pyDeltaRCM.py index d7981086..afc550c1 100644 --- a/run_pyDeltaRCM.py +++ b/run_pyDeltaRCM.py @@ -3,7 +3,7 @@ if __name__ == '__main__': - delta = DeltaModel(input_file = os.path.join(os.getcwd(), 'tests', 'test.yaml')) + delta = DeltaModel() for time in range(0, 1): delta.update() diff --git a/tests/test_consistent.py b/tests/test_consistent.py index 5cb44e3e..c8245b53 100644 --- a/tests/test_consistent.py +++ b/tests/test_consistent.py @@ -6,7 +6,10 @@ import os import numpy as np +from pyDeltaRCM import DeltaModel + from utilities import test_DeltaModel +import utilities # need to create a simple case of pydeltarcm object to test these functions @@ -18,3 +21,49 @@ def test_bed_after_one_update(test_DeltaModel): _exp = np.array([-1., -0.840265, -0.9976036, -1., -1.]) assert np.all(test_DeltaModel.eta[:5, 4] == pytest.approx(_exp)) + + +def test_bed_after_ten_updates(test_DeltaModel): + + for _ in range(0, 10): + test_DeltaModel.update() + + # slice is: test_DeltaModel.eta[:5, 4] + # print(test_DeltaModel.eta[:5, 4]) + + _exp = np.array([1.7, 0.83358884, -0.9256229, -1., -1.]) + assert np.all(test_DeltaModel.eta[:5, 4] == pytest.approx(_exp)) + + +def test_long_multi_validation(tmp_path): + # IndexError on corner. + + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'seed', 42) + utilities.write_parameter_to_file(f, 'Length', 600.) + utilities.write_parameter_to_file(f, 'Width', 600.) + utilities.write_parameter_to_file(f, 'dx', 5) + utilities.write_parameter_to_file(f, 'Np_water', 10) + utilities.write_parameter_to_file(f, 'Np_sed', 10) + utilities.write_parameter_to_file(f, 'f_bedload', 0.05) + f.close() + delta = DeltaModel(input_file=p) + + for _ in range(0, 3): + delta.update() + + # slice is: test_DeltaModel.eta[:5, 62] + # print(delta.eta[:5, 62]) + + _exp1 = np.array([-4.971009, -3.722004, -4.973, -3.7240038, -3.7250037]) + assert np.all(delta.eta[:5, 62] == pytest.approx(_exp1)) + + for _ in range(0, 10): + delta.update() + + # slice is: test_DeltaModel.eta[:5, 4] + print(delta.eta[:5, 62]) + + _exp2 = np.array([-4.971052, -2.0813923, -2.0824013, -4.6614914, -1.5570664]) + assert np.all(delta.eta[:5, 62] == pytest.approx(_exp2)) diff --git a/tests/test_deltaRCM_tools.py b/tests/test_deltaRCM_tools.py index 5aa62116..016b5ecf 100644 --- a/tests/test_deltaRCM_tools.py +++ b/tests/test_deltaRCM_tools.py @@ -6,12 +6,18 @@ import os import numpy as np +import glob + +from pyDeltaRCM.model import DeltaModel + from utilities import test_DeltaModel +import utilities def test_run_one_timestep(test_DeltaModel): test_DeltaModel.run_one_timestep() # basically assume sediment has been added at inlet + assert test_DeltaModel.H_SL == 0.0 assert test_DeltaModel.qs[0, 4] != 0. @@ -19,3 +25,186 @@ def test_finalize_timestep(test_DeltaModel): test_DeltaModel.finalize_timestep() # check that sea level rose as expected assert test_DeltaModel.H_SL == 0.3 + + +def test_verbose_printing_0(tmp_path, capsys): + """ + This test should create the log, and then print nothing at all. + """ + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'out_dir', tmp_path / 'out_dir') + utilities.write_parameter_to_file(f, 'verbose', 0) + utilities.write_parameter_to_file(f, 'Length', 10.0) + utilities.write_parameter_to_file(f, 'Width', 10.0) + utilities.write_parameter_to_file(f, 'dx', 1.0) + utilities.write_parameter_to_file(f, 'L0_meters', 1.0) + utilities.write_parameter_to_file(f, 'itermax', 1) + utilities.write_parameter_to_file(f, 'Np_water', 10) + utilities.write_parameter_to_file(f, 'N0_meters', 2.0) + utilities.write_parameter_to_file(f, 'h0', 1.0) + utilities.write_parameter_to_file(f, 'Np_sed', 10) + utilities.write_parameter_to_file(f, 'f_bedload', 0.5) + utilities.write_parameter_to_file(f, 'C0_percent', 0.1) + f.close() + delta = DeltaModel(input_file=p) + assert os.path.isfile(os.path.join(delta.prefix, 'pyDeltaRCM_output.nc')) + assert len(glob.glob(os.path.join(delta.prefix, '*.log')) + ) == 1 # log file exists + delta.update() + captd = capsys.readouterr() + assert not 'Timestep: 0.0' in captd.out + + +def test_verbose_printing_1(tmp_path, capsys): + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'out_dir', tmp_path / 'out_dir') + utilities.write_parameter_to_file(f, 'verbose', 1) + utilities.write_parameter_to_file(f, 'Length', 10.0) + utilities.write_parameter_to_file(f, 'Width', 10.0) + utilities.write_parameter_to_file(f, 'dx', 1.0) + utilities.write_parameter_to_file(f, 'L0_meters', 1.0) + utilities.write_parameter_to_file(f, 'itermax', 1) + utilities.write_parameter_to_file(f, 'Np_water', 10) + utilities.write_parameter_to_file(f, 'N0_meters', 2.0) + utilities.write_parameter_to_file(f, 'h0', 1.0) + utilities.write_parameter_to_file(f, 'Np_sed', 10) + utilities.write_parameter_to_file(f, 'f_bedload', 0.5) + utilities.write_parameter_to_file(f, 'C0_percent', 0.1) + f.close() + delta = DeltaModel(input_file=p) + captd1 = capsys.readouterr() + delta.update() + captd2 = capsys.readouterr() + assert captd1.out == '' + assert len(glob.glob(os.path.join(delta.prefix, '*.log')) + ) == 1 # log file exists + assert 'Timestep: 0.0' in captd2.out # if verbose >= 1 + assert not 'Creating output directory' in captd2.out # goes to logger + + +def test_verbose_printing_2(tmp_path, capsys): + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'out_dir', tmp_path / 'out_dir') + utilities.write_parameter_to_file(f, 'verbose', 2) + utilities.write_parameter_to_file(f, 'seed', 10) + utilities.write_parameter_to_file(f, 'Length', 10.0) + utilities.write_parameter_to_file(f, 'Width', 10.0) + utilities.write_parameter_to_file(f, 'dx', 1.0) + utilities.write_parameter_to_file(f, 'L0_meters', 1.0) + utilities.write_parameter_to_file(f, 'itermax', 1) + utilities.write_parameter_to_file(f, 'Np_water', 10) + utilities.write_parameter_to_file(f, 'N0_meters', 2.0) + utilities.write_parameter_to_file(f, 'h0', 1.0) + utilities.write_parameter_to_file(f, 'Np_sed', 10) + utilities.write_parameter_to_file(f, 'f_bedload', 0.5) + utilities.write_parameter_to_file(f, 'C0_percent', 0.1) + f.close() + delta = DeltaModel(input_file=p) + captd1 = capsys.readouterr() + delta.update() + captd2 = capsys.readouterr() + assert len(glob.glob(os.path.join(delta.prefix, '*.log')) + ) == 1 # log file exists + assert 'Setting random seed to' in captd1.out # if verbose >= 2 + assert 'Timestep: 0.0' in captd2.out # if verbose >= 1 + assert delta.seed == 10 + + +def test_logger_has_initialization_lines(tmp_path): + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'out_dir', tmp_path / 'out_dir') + utilities.write_parameter_to_file(f, 'verbose', 1) + utilities.write_parameter_to_file(f, 'seed', 10) + utilities.write_parameter_to_file(f, 'Length', 10.0) + utilities.write_parameter_to_file(f, 'Width', 10.0) + utilities.write_parameter_to_file(f, 'dx', 1.0) + utilities.write_parameter_to_file(f, 'L0_meters', 1.0) + utilities.write_parameter_to_file(f, 'itermax', 1) + utilities.write_parameter_to_file(f, 'Np_water', 10) + utilities.write_parameter_to_file(f, 'N0_meters', 2.0) + utilities.write_parameter_to_file(f, 'h0', 1.0) + utilities.write_parameter_to_file(f, 'Np_sed', 10) + utilities.write_parameter_to_file(f, 'f_bedload', 0.5) + utilities.write_parameter_to_file(f, 'C0_percent', 0.1) + f.close() + delta = DeltaModel(input_file=p) + _logs = glob.glob(os.path.join(delta.prefix, '*.log')) + assert len(_logs) == 1 # log file exists + with open(_logs[0], 'r') as _logfile: + _lines = _logfile.readlines() + _lines = ' '.join(_lines) # collapse to a single string + assert 'Setting model constant' in _lines + assert 'Setting random seed to: 10' in _lines + assert 'Random seed is: 10' in _lines + assert 'Creating model domain' in _lines + assert 'Generating netCDF file for output grids' in _lines + assert 'Output netCDF file created' in _lines + assert 'Model initialization complete' in _lines + + +def test_logger_has_timestep_lines(tmp_path): + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'out_dir', tmp_path / 'out_dir') + utilities.write_parameter_to_file(f, 'verbose', 1) + utilities.write_parameter_to_file(f, 'seed', 10) + utilities.write_parameter_to_file(f, 'Length', 10.0) + utilities.write_parameter_to_file(f, 'Width', 10.0) + utilities.write_parameter_to_file(f, 'dx', 1.0) + utilities.write_parameter_to_file(f, 'L0_meters', 1.0) + utilities.write_parameter_to_file(f, 'itermax', 1) + utilities.write_parameter_to_file(f, 'Np_water', 10) + utilities.write_parameter_to_file(f, 'N0_meters', 2.0) + utilities.write_parameter_to_file(f, 'h0', 1.0) + utilities.write_parameter_to_file(f, 'Np_sed', 10) + utilities.write_parameter_to_file(f, 'f_bedload', 0.5) + utilities.write_parameter_to_file(f, 'C0_percent', 0.1) + f.close() + delta = DeltaModel(input_file=p) + _logs = glob.glob(os.path.join(delta.prefix, '*.log')) + assert len(_logs) == 1 # log file exists + for _ in range(0, 2): + delta.update() + assert len(_logs) == 1 # log file exists, still only one + with open(_logs[0], 'r') as _logfile: + _lines = _logfile.readlines() + _lines = ' '.join(_lines) # collapse to a single string + assert '---- Timestep 0.0 ----' in _lines + assert '---- Timestep 1.0 ----' in _lines + assert not '---- Timestep 2.0 ----' in _lines + + +@pytest.mark.xfail(raises=ValueError, strict=True) +def test_logger_random_seed_always_recorded(tmp_path): + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'out_dir', tmp_path / 'out_dir') + utilities.write_parameter_to_file(f, 'verbose', 0) + # do not set the seed explicitly, let it be set by the model + # utilities.write_parameter_to_file(f, 'seed', None) + f.close() + delta = DeltaModel(input_file=p) + _logs = glob.glob(os.path.join(delta.prefix, '*.log')) + assert len(_logs) == 1 # log file exists + with open(_logs[0], 'r') as _logfile: + _lines = _logfile.readlines() + _joinedlines = ' '.join(_lines) # collapse to a single string + assert 'Random seed is: ' in _joinedlines + + # determine the index of the line + _idx = ['Random seed is: ' in _l for _l in _lines] + assert sum(_idx) == 1 # one and only one True in list + _idx = _idx.index(True) + + # try to covert to int, otherwise fail + _seed = _lines[_idx].split(':')[-1] # pull the seed value + try: + _intseed = int(_seed) + except ValueError: + raise ValueError('Could not convert the seed to int') + + assert _intseed >= 0 diff --git a/tests/test_shared_tools.py b/tests/test_shared_tools.py index cc993277..eef75533 100644 --- a/tests/test_shared_tools.py +++ b/tests/test_shared_tools.py @@ -6,18 +6,12 @@ import os import numpy as np -# from pyDeltaRCM.deltaRCM_driver import pyDeltaRCM +from pyDeltaRCM.model import DeltaModel from pyDeltaRCM import shared_tools +import utilities from utilities import test_DeltaModel -# need to create a simple case of pydeltarcm object to test these functions -# delta = DeltaModel(input_file=os.path.join(os.getcwd(), 'tests', 'test.yaml')) - -# now that it is initiated can access the shared_tools via the inherited object -# delta._delta.**shared_tools_function** - - def test_set_random_assignments(test_DeltaModel): """ Test for function shared_tools.get_random_uniform and @@ -232,3 +226,102 @@ def test_version_is_valid(): assert type(v) is str dots = [i for i, c in enumerate(v) if c == '.'] assert len(dots) == 2 + + +@pytest.mark.xfail(raises=IndexError, strict=True) +def test_limit_inds_error(tmp_path): + """IndexError on corner. + + This test throws an error by trying to index cell 1800 of a 30x60 array. + This exceeds the limit of the array. I suspect this is a bug with the + unravel in shared_tools. + + The xfail should be removed when the bug is fixed. + """ + + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'seed', 42) + utilities.write_parameter_to_file(f, 'Length', 30.) + utilities.write_parameter_to_file(f, 'Width', 60.) + utilities.write_parameter_to_file(f, 'dx', 1) + utilities.write_parameter_to_file(f, 'verbose', 1) + utilities.write_parameter_to_file(f, 'Np_water', 20) + utilities.write_parameter_to_file(f, 'Np_sed', 20) + utilities.write_parameter_to_file(f, 'f_bedload', 0.65) + f.close() + delta = DeltaModel(input_file=p) + + for _ in range(0, 2): + delta.update() + + # slice is: test_DeltaModel.eta[:5, 4] + print(delta.eta[:5, 2]) + + _exp = np.array([1.7, 0.83358884, -0.9256229, -1., -1.]) + assert np.all(delta.eta[:5, 2] == pytest.approx(_exp)) + + +""" +This test cannot be enabled because it causes a segfault. For some reason, +this configuration results in an index error (like the below test) if you run +the config as a normal model run, but produces a segfault inside the test. + +@pytest.mark.xfail(raises=IndexError, strict=True) +def test_limits_inds_error_segfault_error(tmp_path): + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'seed', 43) + utilities.write_parameter_to_file(f, 'Length', 30.) + utilities.write_parameter_to_file(f, 'Width', 60.) + utilities.write_parameter_to_file(f, 'dx', 1) + utilities.write_parameter_to_file(f, 'verbose', 1) + utilities.write_parameter_to_file(f, 'Np_water', 20) + utilities.write_parameter_to_file(f, 'Np_sed', 20) + utilities.write_parameter_to_file(f, 'f_bedload', 0.65) + f.close() + delta = DeltaModel(input_file=p) + + for _ in range(0, 2): + delta.update() + + # slice is: test_DeltaModel.eta[:5, 4] + print(delta.eta[:5, 2]) + + _exp = np.array([1.7, 0.83358884, -0.9256229, -1., -1.]) + assert np.all(delta.eta[:5, 2] == pytest.approx(_exp)) + + +@pytest.mark.xfail(raises=IndexError, strict=True) +def test_limit_inds_error(tmp_path): + # IndexError on corner. + + # This test throws an error by trying to index cell 1800 of a 30x60 array. + # This exceeds the limit of the array. I suspect this is a bug with the + # unravel in shared_tools. + + # The xfail should be removed when the bug is fixed. + + file_name = 'user_parameters.yaml' + p, f = utilities.create_temporary_file(tmp_path, file_name) + utilities.write_parameter_to_file(f, 'seed', 42) + utilities.write_parameter_to_file(f, 'Length', 20.) + utilities.write_parameter_to_file(f, 'Width', 10.) + utilities.write_parameter_to_file(f, 'dx', 2) + utilities.write_parameter_to_file(f, 'verbose', 1) + utilities.write_parameter_to_file(f, 'Np_water', 20) + utilities.write_parameter_to_file(f, 'Np_sed', 20) + utilities.write_parameter_to_file(f, 'f_bedload', 0.65) + f.close() + delta = DeltaModel(input_file=p) + + for _ in range(0, 2): + delta.update() + + # slice is: test_DeltaModel.eta[:5, 4] + print(delta.eta[:5, 2]) + + _exp = np.array([1.7, 0.83358884, -0.9256229, -1., -1.]) + assert np.all(delta.eta[:5, 2] == pytest.approx(_exp)) + +""" \ No newline at end of file