pyDeltaRCM 2.1.10__tar.gz → 2.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. {pydeltarcm-2.1.10/pyDeltaRCM.egg-info → pydeltarcm-2.2.0}/PKG-INFO +1 -1
  2. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/custom_saving.rst +14 -9
  3. pydeltarcm-2.2.0/docs/source/examples/gotcha_simulataneous_models.rst +62 -0
  4. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/index.rst +8 -0
  5. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/info/outputfile.rst +20 -14
  6. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/_version.py +1 -1
  7. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/hook_tools.py +1 -1
  8. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/init_tools.py +207 -57
  9. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/iteration_tools.py +35 -4
  10. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/model.py +44 -36
  11. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0/pyDeltaRCM.egg-info}/PKG-INFO +1 -1
  12. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM.egg-info/SOURCES.txt +1 -0
  13. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/integration/test_checkpointing.py +321 -255
  14. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/integration/test_consistent_outputs.py +70 -9
  15. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/integration/test_timing_triggers.py +11 -11
  16. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_init_tools.py +266 -28
  17. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_iteration_tools.py +85 -9
  18. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/LICENSE +0 -0
  19. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/MANIFEST.in +0 -0
  20. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/README.rst +0 -0
  21. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/.nojekyll +0 -0
  22. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/_resources/checkpoint/checkpoint.npz +0 -0
  23. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/_resources/checkpoint.yaml +0 -0
  24. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/_static/style.css +0 -0
  25. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/_templates/page.html +0 -0
  26. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/conf.py +0 -0
  27. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/basic_runs.rst +0 -0
  28. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/custom_class_preprocessor.rst +0 -0
  29. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/custom_yaml.rst +0 -0
  30. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/modelzoo.rst +0 -0
  31. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/overwrite_topo_diffusion.rst +0 -0
  32. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/resume_from_checkpoint.rst +0 -0
  33. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/simple_example.ipynb +0 -0
  34. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/slight_slope.rst +0 -0
  35. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/subsidence_region.rst +0 -0
  36. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/updating_boundary_conditions.rst +0 -0
  37. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/variable_bedload.rst +0 -0
  38. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/examples/variable_velocity.rst +0 -0
  39. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/guides/10min.rst +0 -0
  40. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/guides/advanced_configuration_guide.inc +0 -0
  41. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/guides/developer_guide.rst +0 -0
  42. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/guides/getting_started.rst +0 -0
  43. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/guides/subsidence_guide.inc +0 -0
  44. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/guides/user_guide.rst +0 -0
  45. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/index.rst +0 -0
  46. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/info/hydrodynamics.rst +0 -0
  47. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/info/index.rst +0 -0
  48. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/info/initialization.rst +0 -0
  49. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/info/modeltime.rst +0 -0
  50. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/info/morphodynamics.rst +0 -0
  51. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/info/yamlparameters.rst +0 -0
  52. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/meta/citing.rst +0 -0
  53. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/meta/conduct.rst +0 -0
  54. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/meta/contributing.rst +0 -0
  55. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/meta/installing.rst +0 -0
  56. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/meta/license.rst +0 -0
  57. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/meta/usedby.rst +0 -0
  58. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/debug_tools/debug_demo.py +0 -0
  59. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/guides/10min_demo.py +0 -0
  60. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/guides/cover.py +0 -0
  61. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/guides/output_file.py +0 -0
  62. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/init_tools/domain_basin_inlet_depth.py +0 -0
  63. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/init_tools/domain_inlet_geometry.py +0 -0
  64. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/init_tools/domain_parameters.py +0 -0
  65. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/init_tools/domain_size_compare.py +0 -0
  66. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/modeltime/_base.py +0 -0
  67. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/modeltime/four_year_condensed_plot.py +0 -0
  68. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/modeltime/four_year_plot.py +0 -0
  69. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/modeltime/one_year_plot.py +0 -0
  70. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/sed_tools/_initial_bed_state.py +0 -0
  71. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/sed_tools/route_all_mud_parcels.py +0 -0
  72. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/sed_tools/route_all_sand_parcels.py +0 -0
  73. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/sed_tools/sediment_weights_examples.py +0 -0
  74. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/sed_tools/topo_diffusion.py +0 -0
  75. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/water_tools/_accumulate_free_surface_walks.py +0 -0
  76. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/water_tools/_check_for_loops.py +0 -0
  77. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/water_tools/_smooth_free_surface.py +0 -0
  78. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/water_tools/compute_free_surface_inputs.py +0 -0
  79. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/water_tools/compute_free_surface_outputs.py +0 -0
  80. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/water_tools/flooding_correction.py +0 -0
  81. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/water_tools/run_water_iteration.py +0 -0
  82. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/pyplots/water_tools/water_weights_examples.py +0 -0
  83. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/debug_tools/index.rst +0 -0
  84. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/hook_tools/index.rst +0 -0
  85. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/index.rst +0 -0
  86. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/init_tools/index.rst +0 -0
  87. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/iteration_tools/index.rst +0 -0
  88. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/model/index.rst +0 -0
  89. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/model/model_hooks.rst +0 -0
  90. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/model/yaml_defaults.rst +0 -0
  91. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/preprocessor/index.rst +0 -0
  92. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/sed_tools/index.rst +0 -0
  93. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/shared_tools/index.rst +0 -0
  94. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/docs/source/reference/water_tools/index.rst +0 -0
  95. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/__init__.py +0 -0
  96. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/__main__.py +0 -0
  97. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/debug_tools.py +0 -0
  98. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/default.yml +0 -0
  99. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/preprocessor.py +0 -0
  100. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/sed_tools.py +0 -0
  101. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/shared_tools.py +0 -0
  102. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM/water_tools.py +0 -0
  103. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM.egg-info/dependency_links.txt +0 -0
  104. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM.egg-info/entry_points.txt +0 -0
  105. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM.egg-info/requires.txt +0 -0
  106. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyDeltaRCM.egg-info/top_level.txt +0 -0
  107. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/pyproject.toml +0 -0
  108. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/setup.cfg +0 -0
  109. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/__init__.py +0 -0
  110. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type.png +0 -0
  111. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_list_index.png +0 -0
  112. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_list_mix_tuple_index.png +0 -0
  113. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_list_tuple.png +0 -0
  114. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_multiple_diff_args.png +0 -0
  115. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_multiple_diff_kwargs.png +0 -0
  116. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_multiple_index_calls.png +0 -0
  117. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_no_grid.png +0 -0
  118. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_single_index.png +0 -0
  119. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_cell_type_single_tuple.png +0 -0
  120. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_velocity.png +0 -0
  121. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_domain_withlabel.png +0 -0
  122. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_iwalk.png +0 -0
  123. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_plot_multiple_subplots.png +0 -0
  124. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_show_line_pts_Nx2_array.png +0 -0
  125. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/imgs_baseline/test_show_line_set_points.png +0 -0
  126. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/integration/__init__.py +0 -0
  127. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/integration/test_cli.py +0 -0
  128. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_debug_tools.py +0 -0
  129. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_logging.py +0 -0
  130. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_model.py +0 -0
  131. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_preprocessor.py +0 -0
  132. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_sed_tools.py +0 -0
  133. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_shared_tools.py +0 -0
  134. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/test_water_tools.py +0 -0
  135. {pydeltarcm-2.1.10 → pydeltarcm-2.2.0}/tests/utilities.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyDeltaRCM
3
- Version: 2.1.10
3
+ Version: 2.2.0
4
4
  Summary: Python version of original Matlab DeltaRCM.
5
5
  Author-email: Andrew Moodie <amoodie@tamu.edu>
6
6
  Maintainer-email: Andrew Moodie <amoodie@tamu.edu>
@@ -17,11 +17,11 @@ For example, ``self._save_fig_list['active_layer'] = ['active_layer']`` will pro
17
17
  When adding variables or metadata to be initialized and subsequently saved in the output netCDF, the key-value pair relationship is as follows.
18
18
  The key added to ``self._save_var_list`` is the name of the variable as it will be recorded in the netCDF file, this *does not* have to correspond to the name of an attribute in the model.
19
19
  To add a variable to the metadata, a key must be added to ``self._save_var_list['meta']``.
20
- The expected value for a given key is a list containing strings indicating the model attribute to be saved, its units, the variable type, and lastly the variable dimensions (e.g., ``['active_layer', 'fraction', 'f4', ('time', 'x', 'y')]`` for the active layer).
20
+ The expected value for a given key is a list containing strings indicating the model attribute to be saved, its units, the variable type, and lastly the variable dimensions (e.g., ``['active_layer', 'fraction', 'f4', ('seconds', 'x', 'y')]`` for the active layer).
21
21
 
22
22
  .. important::
23
23
 
24
- The dimensions of the custom variable being specified must match *exactly* with one of the three standard dimensions: `x`, `y`, `time`.
24
+ The dimensions of the custom variable being specified must match *exactly* with one of the three standard dimensions: `x`, `y`, `seconds`.
25
25
  Use of an invalid dimension will result in an error.
26
26
 
27
27
  An example of using the hook and creating a model subclass to customize the figures, gridded variables, and metadata being saved is provided below.
@@ -48,14 +48,19 @@ An example of using the hook and creating a model subclass to customize the figu
48
48
  ... self._save_fig_list['active_layer'] = ['active_layer']
49
49
  ...
50
50
  ... # save the active layer grid each save_dt w/ a short name
51
- ... self._save_var_list['actlay'] = ['active_layer', 'fraction',
52
- ... 'f4', ('time',
53
- ... 'x', 'y')]
51
+ ... self._save_var_list['actlay'] = [
52
+ ... 'active_layer', 'fraction',
53
+ ... 'f4', ('seconds', 'x', 'y'),
54
+ ... 'channel_bottom__sediment__active_layer'
55
+ ... ]
54
56
  ...
55
57
  ... # save number of water parcels w/ a long name
56
- ... self._save_var_list['meta']['water_parcels'] = ['Np_water',
57
- ... 'parcels',
58
- ... 'i8', ()]
58
+ ... self._save_var_list['meta']['water_parcels'] = [
59
+ ... 'Np_water',
60
+ ... 'parcels',
61
+ ... 'i8', (),
62
+ ... 'model_water__number_parcels'
63
+ ... ]
59
64
 
60
65
  Next, we instantiate the model class.
61
66
 
@@ -83,4 +88,4 @@ For simplicity we will just check that the appropriate parameters were added to
83
88
  {'active_layer': ['active_layer']}
84
89
 
85
90
  >>> print(mdl._save_var_list)
86
- {'meta': {'water_parcels': ['Np_water', 'parcels', 'i8', ()]}, 'actlay': ['active_layer', 'fraction', 'f4', ('time', 'x', 'y')]}
91
+ {'meta': {'water_parcels': ['Np_water', 'parcels', 'i8', (), 'model_water__number_parcels']}, 'actlay': ['active_layer', 'fraction', 'f4', ('seconds', 'x', 'y'), 'channel_bottom__sediment__active_layer']}
@@ -0,0 +1,62 @@
1
+ Instantiating and running two models iteratively on the same core is not reproducible
2
+ =====================================================================================
3
+
4
+
5
+ You cannot run models "simultaneously" and get reproducible results.
6
+
7
+ In an ideal world, two models with same seed should give same result,
8
+ regardless of how they are run. But if two models are called intermittently,
9
+ then the result is not reproducible (at least on a per-model basis) because
10
+ the random-number generator is thrown out of sync with respect to the single
11
+ model and seed. More explanation below.
12
+
13
+ .. note::
14
+
15
+ As of 03/2026, numba does not implement random number generation as an
16
+ object, and so we cannot aviod this "gotcha".
17
+
18
+ .. code::
19
+
20
+ # initialize models
21
+ test1 = DeltaModel()
22
+ test2 = DeltaModel()
23
+
24
+ for _ in range(0, 5):
25
+ test1.update()
26
+ test2.update()
27
+
28
+ test1.finalize()
29
+ test2.finalize()
30
+
31
+ # test that gives same result (WILL FAIL)
32
+ difference = test1.eta - test2.eta
33
+ assert np.all(difference == 0)
34
+
35
+ .. DEVNOTE: see test in tests/integration/test_consistent_outputs.py in TestConsistentOutputsSameSeed called test_same_models_simulataneous_not_parallel
36
+
37
+ **The above code will fail to generate reproducible results.**
38
+
39
+ The problem is that both test and test2 access the same underlying random
40
+ number generator in Numba, and therefore follow different trajectories over
41
+ time. The only way around this is to instantiate the models sequentially
42
+ (resetting the seed via the instantiation of the second one after finishing
43
+ the first one), or instantiating the objects in subprocesses (this is what
44
+ the `preprocessor` does for parallel runs).
45
+
46
+ Of course, if you don't care about reproducibility at the moment (e.g., prototyping, testing approaches, etc), you can totally use the above approach. **Your final model code for analysis should be reproducible and not use this approach!**
47
+
48
+
49
+ The below code will work to give reproducible results.
50
+
51
+ .. code::
52
+
53
+ test1 = DeltaModel(input_file=p1)
54
+ for _ in range(0, 5):
55
+ test1.update()
56
+ test1.finalize()
57
+
58
+ test2 = DeltaModel(input_file=p2)
59
+ for _ in range(0, 5):
60
+ test2.update()
61
+ test2.finalize()
62
+
@@ -11,6 +11,14 @@ Running the model
11
11
  basic_runs
12
12
  resume_from_checkpoint
13
13
 
14
+ Common "gotchas"
15
+ ----------------
16
+
17
+ .. toctree::
18
+ :maxdepth: 1
19
+
20
+ gotcha_simulataneous_models
21
+
14
22
 
15
23
  Modifying initial conditions
16
24
  ----------------------------
@@ -10,30 +10,35 @@ Gridded Variables
10
10
 
11
11
  In any given run, the saving parameters "save_<var>_grids" control whether or
12
12
  not that 2-D grid variable (e.g. velocity) is saved to the netCDF4 file. In
13
- the netCDF4 file, a 3-D array with the dimensions `time` :math:`\times`
13
+ the netCDF4 file, a 3-D array with the dimensions `seconds` :math:`\times`
14
14
  `x` :math:`\times` `y` is created for each 2-D grid variable that is set to
15
15
  be saved. Note that `x` is the *downstream* coordinate, rather than the
16
16
  Cartesian `x` when displaying the grid. The appropriate units for all
17
17
  variables are stored: for example "meters per second" for the *velocity*
18
- grid.
18
+ grid. All variables include a description via the `long_name` attribute.
19
19
 
20
- .. note::
20
+ .. important::
21
21
 
22
- The format of the output netCDF file coordinate changed in `v2.1.0`. The
23
- old format is documented
24
- in :attr:`~pyDeltaRCM.model.DeltaModel.legacy_netcdf`, and that input
25
- parameter `legacy_netcdf` can be used to create on output netcdf file with
26
- the old coordinate configuration.
22
+ The format of the output netCDF file coordinates changed in `v2.2.0`. The
23
+ old format (up to v2.1.9) is documented
24
+ in :attr:`~pyDeltaRCM.model.DeltaModel.legacy_netcdf`, and the input
25
+ parameter `legacy_netcdf` can be used to create an output netcdf file with
26
+ the old coordinate configuration. The output format for pyDeltaRCM v2.1.0
27
+ and earlier is deprecated and has been removed. Changing to the new output
28
+ format should be a small change for most users, with only the name of the
29
+ temporal dimension and the metadata subgroup changing in the new output.
27
30
 
28
31
 
29
32
  Grid Coordinates
30
33
  ================
31
34
 
32
- Grid coordinates are specified in the variables `time`, `x`, and `y` in the output netCDF4 file.
33
- These arrays are 1D arrays, which specify the location of each cell in the domain in *dimensional* coordinates (e.g., meters).
34
- In the downstream direction, the distance of each cell from the inlet boundary is specified in `x` in meters.
35
- Similarly, the cross-domain distance is specified in `y` in meters.
36
- Lastly, the `time` variable is stored as a 1D array with model `time` in seconds.
35
+ Grid coordinates are specified in the variables `seconds`, `x`, and `y` in the
36
+ output netCDF4 file. These arrays are 1D arrays, which specify the location
37
+ of each cell in the domain in *dimensional* coordinates (e.g., meters). In
38
+ the downstream direction, the distance of each cell from the inlet boundary
39
+ is specified in `x` in meters. Similarly, the cross-domain distance is
40
+ specified in `y` in meters. Lastly, the `seconds` variable is stored as a 1D
41
+ array recording model elapsed time in seconds.
37
42
 
38
43
 
39
44
  Model Metadata
@@ -53,6 +58,7 @@ saved as metadata are the following:
53
58
  - Sediment concentration: `C0_percent`
54
59
  - Characteristic Velocity: `u0`
55
60
  - If subsidence is enabled:
61
+
56
62
  - Subsidence start time: `start_subsidence`
57
63
  - Subsidence rate: `sigma`
58
64
 
@@ -66,7 +72,7 @@ library. These libraries range from the
66
72
  to higher-level libraries such as
67
73
  `xarray <https://github.com/pydata/xarray>`_. For deltas, and specifically
68
74
  *pyDeltaRCM*, there is also a package under development called
69
- `DeltaMetrics <https://github.com/DeltaRCM/DeltaMetrics>`_,
75
+ `sandplover <https://github.com/sandpiper-toolchain/sandplover>`_,
70
76
  that is being designed to help post-process and analyze *pyDeltaRCM* outputs.
71
77
 
72
78
 
@@ -3,4 +3,4 @@ def __version__() -> str:
3
3
  Private version declaration, gets assigned to pyDeltaRCM.__version__
4
4
  during import
5
5
  """
6
- return "2.1.10"
6
+ return "2.2.0"
@@ -237,7 +237,7 @@ class hook_tools(abc.ABC):
237
237
  .. note::
238
238
 
239
239
  For a vector of time-varying metadata, the dimension
240
- should be specified as ('total_time').
240
+ should be specified as ('time').
241
241
 
242
242
  Expected format for time varying grid entries as keys within the
243
243
  `self._save_var_list` dictionary:
@@ -225,9 +225,9 @@ class init_tools(abc.ABC):
225
225
  self.out_dir = self._input_file_vars["out_dir"]
226
226
  self.verbose = self._input_file_vars["verbose"]
227
227
  if self._input_file_vars["legacy_netcdf"]:
228
- self._netcdf_coords = ("total_time", "length", "width")
229
- else:
230
228
  self._netcdf_coords = ("time", "x", "y")
229
+ else:
230
+ self._netcdf_coords = ("seconds", "x", "y")
231
231
 
232
232
  def process_input_to_model(self) -> None:
233
233
  """Process input file to model variables.
@@ -659,6 +659,22 @@ class init_tools(abc.ABC):
659
659
  file_path = os.path.join(directory, filename)
660
660
  _msg = "Target output NetCDF4 file: {file}".format(file=file_path)
661
661
  self.log_info(_msg, verbosity=2)
662
+ if not self._legacy_netcdf:
663
+ _sandsuet_version = "1.0.0"
664
+ _msg = "Output file in sandsuet version {ver} schema".format(
665
+ ver=_sandsuet_version
666
+ )
667
+ else:
668
+ _msg = "Output file in legacy schema"
669
+ warnings.warn(
670
+ "Creating output netcdf file in legacy schema. This format is "
671
+ "provided as a convenience for users who are currently "
672
+ "relying on workflows that use an old format of netcdf file. "
673
+ "It will be removed in the future. Any new workflows should "
674
+ "leverage the sandsuet formatted data specification "
675
+ "(i.e., `legacy_netcdf=False`)."
676
+ )
677
+ self.log_info(_msg, verbosity=1)
662
678
 
663
679
  if (os.path.exists(file_path)) and (self._clobber_netcdf is False):
664
680
  raise FileExistsError(
@@ -678,6 +694,8 @@ class init_tools(abc.ABC):
678
694
  self.output_netcdf.source = "pyDeltaRCM v{ver}".format(
679
695
  ver=self.__pyDeltaRCM_version__
680
696
  )
697
+ if not self._legacy_netcdf:
698
+ self.output_netcdf.sandsuet_version = _sandsuet_version
681
699
 
682
700
  # create master dimensions (pulls from `self._netcdf_coords`)
683
701
  self.output_netcdf.createDimension(self._netcdf_coords[1], self.L)
@@ -685,77 +703,158 @@ class init_tools(abc.ABC):
685
703
  self.output_netcdf.createDimension(self._netcdf_coords[0], None)
686
704
 
687
705
  # create master coordinates (as netCDF variables)
688
- time = self.output_netcdf.createVariable(
689
- "time", "f4", (self._netcdf_coords[0],)
690
- )
691
- time.units = "second"
692
-
693
706
  if self._legacy_netcdf:
694
- # old format is 2d array x and y
695
- x = self.output_netcdf.createVariable(
696
- "x", "f4", self._netcdf_coords[1:]
707
+ time = self.output_netcdf.createVariable(
708
+ "time", "f4", (self._netcdf_coords[0],)
697
709
  )
698
- y = self.output_netcdf.createVariable(
699
- "y", "f4", self._netcdf_coords[1:]
700
- )
701
- x[:] = self.x
702
- y[:] = self.y
703
710
 
704
711
  else:
705
- # new output format is 1d x and y
706
- x = self.output_netcdf.createVariable("x", "f4", ("x"))
707
- y = self.output_netcdf.createVariable("y", "f4", ("y"))
708
- x[:] = self.xc
709
- y[:] = self.yc
712
+ time = self.output_netcdf.createVariable(
713
+ "seconds", "f4", (self._netcdf_coords[0],)
714
+ )
715
+ time.units = "second"
710
716
 
717
+ # new output format is 1d x and y
718
+ x = self.output_netcdf.createVariable("x", "f4", ("x"))
719
+ y = self.output_netcdf.createVariable("y", "f4", ("y"))
720
+ x[:] = self.xc
721
+ y[:] = self.yc
711
722
  x.units = "meter"
712
723
  y.units = "meter"
713
724
 
714
- # set up variables for output data grids
715
- def _create_grid_variable(varname, varunits, vartype="f4", vardims=()):
725
+ # set up function to output data grids
726
+ def _create_grid_variable(
727
+ varname, varunits, vartype="f4", vardims=(), varlong=None
728
+ ):
716
729
  _v = self.output_netcdf.createVariable(varname, vartype, vardims)
717
730
  _v.units = varunits
731
+ if varlong is not None:
732
+ # long_name is provided, record it
733
+ _v.long_name = varlong
734
+ else:
735
+ if not self._legacy_netcdf:
736
+ raise ValueError(
737
+ f"long name must be provided for all variables to create a "
738
+ f"sandsuet compliant data output, "
739
+ f"but was not provided for variable '{varname}'."
740
+ )
718
741
 
742
+ # loop through main output data grids
719
743
  _var_list = list(self._save_var_list.keys())
720
- _var_list.remove("meta")
744
+ _var_list.remove("meta") # remove group from list
721
745
  for _val in _var_list:
746
+ if isinstance(self._save_var_list[_val], list):
747
+ ### for now, we silently convert to dictionary format
748
+ # # inputs should be specified as a dictionary
749
+ # warnings.warn(
750
+ # f"Specification format for output data should be `dict`, "
751
+ # f"but was `list`. Converting `list` for one or more variables "
752
+ # f"to `dict` based on item order. This compatability will "
753
+ # f"be removed in a future version."
754
+ # )
755
+ ###
756
+ # do the conversion
757
+ __inlist = self._save_var_list[_val]
758
+ __varname = _val
759
+ __varlong = __inlist[4] if len(__inlist) > 4 else None
760
+ _vardict = dict(
761
+ varname=__varname, # use dict key as varname
762
+ varunits=__inlist[1],
763
+ vartype=__inlist[2],
764
+ vardims=__inlist[3],
765
+ varlong=__varlong,
766
+ )
767
+ else:
768
+ _vardict = self._save_var_list[_val]
769
+
722
770
  _create_grid_variable(
723
- _val,
724
- self._save_var_list[_val][1],
725
- self._save_var_list[_val][2],
726
- self._save_var_list[_val][3],
771
+ varname=_vardict["varname"],
772
+ varunits=_vardict["varunits"],
773
+ vartype=_vardict["vartype"],
774
+ vardims=_vardict["vardims"],
775
+ varlong=_vardict["varlong"],
727
776
  )
728
777
 
729
- # set up metadata group and populate variables
778
+ # find name for subgroup data and make list
779
+ if self._legacy_netcdf:
780
+ self._subgroup_name = "meta"
781
+ else:
782
+ self._subgroup_name = "auxdata"
783
+ self.output_netcdf.createGroup(self._subgroup_name)
784
+
785
+ # set up function to output additional data in subgroup
730
786
  def _create_meta_variable(
731
- varname, varvalue, varunits, vartype="f4", vardims=()
787
+ varname, varvalue, varunits, vartype="f4", vardims=(), varlong=None
732
788
  ):
733
789
  _v = self.output_netcdf.createVariable(
734
- "meta/" + varname, vartype, vardims
790
+ f"{self._subgroup_name}/" + varname, vartype, vardims
735
791
  )
736
792
  _v.units = varunits
793
+ # convert string to value from model attrs
794
+ if isinstance(varvalue, str):
795
+ varvalue = getattr(self, varvalue)
796
+ # fill variable
737
797
  _v[:] = varvalue
798
+ if varlong is not None:
799
+ # long_name is provided, record it
800
+ _v.long_name = varlong
801
+ else:
802
+ if not self._legacy_netcdf:
803
+ raise ValueError(
804
+ f"long name must be provided for all variables to create a "
805
+ f"sandsuet compliant data output, "
806
+ f"but was not provided for variable '{varname}'."
807
+ )
738
808
 
739
- self.output_netcdf.createGroup("meta")
809
+ # loop through additional data in subgroup
740
810
  for _val in self._save_var_list["meta"].keys():
741
- # time-varying initialize w/ None value
742
- if self._save_var_list["meta"][_val][0] is None:
743
- _create_meta_variable(
744
- _val,
745
- self._save_var_list["meta"][_val][0],
746
- self._save_var_list["meta"][_val][1],
747
- self._save_var_list["meta"][_val][2],
748
- self._save_var_list["meta"][_val][3],
811
+ if isinstance(self._save_var_list["meta"][_val], list):
812
+ ### for now, we silently convert to dictionary format
813
+ # inputs should be specified as a dictionary
814
+ # warnings.warn(
815
+ # f"Specification format for output subgroup data should be `dict`, "
816
+ # f"but was `list`. Converting `list` for one or more subgroup variables "
817
+ # f"to `dict` based on item order. This compatability will "
818
+ # f"be removed in a future version."
819
+ # )
820
+ ###
821
+ # do the conversion
822
+ __inlist = self._save_var_list["meta"][_val]
823
+ __varname = _val
824
+ if __inlist[0] is None:
825
+ warnings.warn(
826
+ UserWarning(
827
+ "Specifying `None` for time varying dimensions "
828
+ "of model outputs will soon be deprecated. "
829
+ "Change to specifying the name of the "
830
+ "variable to save a string, and/or convert to "
831
+ "dictionary inputs."
832
+ )
833
+ )
834
+ __varvalue = None
835
+ else:
836
+ __varvalue = getattr(self, __inlist[0])
837
+ __varlong = __inlist[4] if len(__inlist) > 4 else None
838
+ _vardict = dict(
839
+ varname=__varname,
840
+ varvalue=__varvalue,
841
+ varunits=__inlist[1],
842
+ vartype=__inlist[2],
843
+ vardims=__inlist[3],
844
+ varlong=__varlong,
749
845
  )
750
- # for scalars, get the attribute and store it
846
+
751
847
  else:
752
- _create_meta_variable(
753
- _val,
754
- getattr(self, self._save_var_list["meta"][_val][0]),
755
- self._save_var_list["meta"][_val][1],
756
- self._save_var_list["meta"][_val][2],
757
- self._save_var_list["meta"][_val][3],
758
- )
848
+ _vardict = self._save_var_list["meta"][_val]
849
+
850
+ _create_meta_variable(
851
+ varname=_vardict["varname"],
852
+ varvalue=_vardict["varvalue"],
853
+ varunits=_vardict["varunits"],
854
+ vartype=_vardict["vartype"],
855
+ vardims=_vardict["vardims"],
856
+ varlong=_vardict["varlong"],
857
+ )
759
858
 
760
859
  _msg = "Output netCDF file created"
761
860
  self.log_info(_msg, verbosity=2)
@@ -788,17 +887,54 @@ class init_tools(abc.ABC):
788
887
  Sets up the dictionary object for the standard metadata.
789
888
  """
790
889
  # fixed metadata
791
- self._save_var_list["meta"]["L0"] = ["L0", "cells", "i8", ()]
792
- self._save_var_list["meta"]["N0"] = ["N0", "cells", "i8", ()]
793
- self._save_var_list["meta"]["CTR"] = ["CTR", "cells", "i8", ()]
794
- self._save_var_list["meta"]["dx"] = ["dx", "meters", "f4", ()]
795
- self._save_var_list["meta"]["h0"] = ["h0", "meters", "f4", ()]
796
- self._save_var_list["meta"]["hb"] = ["hb", "meters", "f4", ()]
890
+ self._save_var_list["meta"]["L0"] = [
891
+ "L0",
892
+ "cells",
893
+ "i8",
894
+ (),
895
+ "channel_entrance__length",
896
+ ]
897
+ self._save_var_list["meta"]["N0"] = [
898
+ "N0",
899
+ "cells",
900
+ "i8",
901
+ (),
902
+ "channel_entrance__width",
903
+ ]
904
+ self._save_var_list["meta"]["CTR"] = [
905
+ "CTR",
906
+ "cells",
907
+ "i8",
908
+ (),
909
+ "channel_entrance__y_position",
910
+ ]
911
+ self._save_var_list["meta"]["dx"] = [
912
+ "dx",
913
+ "meters",
914
+ "f4",
915
+ (),
916
+ "model_grid_cell_edge__length",
917
+ ]
918
+ self._save_var_list["meta"]["h0"] = [
919
+ "h0",
920
+ "meters",
921
+ "f4",
922
+ (),
923
+ "channel_entrance__depth",
924
+ ]
925
+ self._save_var_list["meta"]["hb"] = [
926
+ "hb",
927
+ "meters",
928
+ "f4",
929
+ (),
930
+ "basin_bottom_initial__depth",
931
+ ]
797
932
  self._save_var_list["meta"]["cell_type"] = [
798
933
  "cell_type",
799
934
  "type",
800
935
  "i8",
801
936
  self._netcdf_coords[1:],
937
+ "model_grid_cell__type",
802
938
  ]
803
939
  # subsidence metadata
804
940
  if self._toggle_subsidence:
@@ -807,37 +943,43 @@ class init_tools(abc.ABC):
807
943
  "seconds",
808
944
  "i8",
809
945
  (),
946
+ "basin_bottom_vertical_rate_of_change__start_time",
810
947
  ]
811
948
  self._save_var_list["meta"]["sigma"] = [
812
949
  "sigma",
813
950
  "meters per timestep",
814
951
  "f4",
815
952
  self._netcdf_coords[1:],
953
+ "basin_bottom__vertical_rate_of_change",
816
954
  ]
817
955
  # time-varying metadata
818
956
  self._save_var_list["meta"]["H_SL"] = [
819
- None,
957
+ "H_SL",
820
958
  "meters",
821
959
  "f4",
822
960
  (self._netcdf_coords[0]),
961
+ "basin_water_surface__elevation",
823
962
  ]
824
963
  self._save_var_list["meta"]["f_bedload"] = [
825
- None,
964
+ "f_bedload",
826
965
  "fraction",
827
966
  "f4",
828
967
  (self._netcdf_coords[0]),
968
+ "channel_entrance_water_sediment_sand__volume_fraction",
829
969
  ]
830
970
  self._save_var_list["meta"]["C0_percent"] = [
831
- None,
971
+ "C0_percent",
832
972
  "percent",
833
973
  "f4",
834
974
  (self._netcdf_coords[0]),
975
+ "channel_entrance__water_sediment__volume_percent",
835
976
  ]
836
977
  self._save_var_list["meta"]["u0"] = [
837
- None,
978
+ "u0",
838
979
  "meters per second",
839
980
  "f4",
840
981
  (self._netcdf_coords[0]),
982
+ "channel_entrance__speed",
841
983
  ]
842
984
 
843
985
  def _load_past_etas(self, checkpoint):
@@ -1030,6 +1172,14 @@ class init_tools(abc.ABC):
1030
1172
  # set object attribute for model
1031
1173
  self.output_netcdf = Dataset(file_path, "r+", format="NETCDF4")
1032
1174
 
1175
+ # find subgroup name, supporting legacy file format
1176
+ if "meta" in self.output_netcdf.groups.keys():
1177
+ self._subgroup_name = "meta"
1178
+ elif "auxdata" in self.output_netcdf.groups.keys():
1179
+ self._subgroup_name = "auxdata"
1180
+ else:
1181
+ self._subgroup_name = self.output_netcdf.groups.keys()[0]
1182
+
1033
1183
  # synch netcdf file
1034
1184
  self.output_netcdf.sync()
1035
1185
 
@@ -254,7 +254,10 @@ class iteration_tools(abc.ABC):
254
254
  self.log_info(_msg, verbosity=1)
255
255
 
256
256
  if self._save_metadata or self._save_any_grids:
257
- self.output_netcdf.variables["time"][save_idx] = self._time
257
+ if self._legacy_netcdf:
258
+ self.output_netcdf.variables["time"][save_idx] = self._time
259
+ else:
260
+ self.output_netcdf.variables["seconds"][save_idx] = self._time
258
261
 
259
262
  # ------------------ Figures ------------------
260
263
  if len(self._save_fig_list) > 0:
@@ -302,8 +305,18 @@ class iteration_tools(abc.ABC):
302
305
  _var_list = list(self._save_var_list.keys())
303
306
  _var_list.remove("meta")
304
307
  for _val in _var_list:
308
+ # get the inital value from either list or dict
309
+ if isinstance(self._save_var_list[_val], list):
310
+ _modelvar = self._save_var_list[_val][0]
311
+ _ncvar = _val
312
+ else:
313
+ _modelvar = self._save_var_list[_val]["varvalue"]
314
+ _ncvar = self._save_var_list[_val]["varname"]
315
+
305
316
  self.save_grids(
306
- _val, getattr(self, self._save_var_list[_val][0]), save_idx
317
+ var_name=_ncvar,
318
+ var=getattr(self, _modelvar),
319
+ save_idx=save_idx,
307
320
  )
308
321
 
309
322
  # ------------------ metadata ------------------
@@ -312,9 +325,27 @@ class iteration_tools(abc.ABC):
312
325
  self.log_info(_msg, verbosity=2)
313
326
 
314
327
  for _val in self._save_var_list["meta"].keys():
328
+ # get the values from either list or dict
329
+ if isinstance(self._save_var_list["meta"][_val], list):
330
+ _dims = len(self._save_var_list["meta"][_val][3])
331
+ _modelvar = self._save_var_list["meta"][_val][0]
332
+ _ncvar = _val
333
+ else:
334
+ _dims = len(self._save_var_list["meta"][_val]["vardims"])
335
+ _modelvar = self._save_var_list["meta"][_val]["varvalue"]
336
+ _ncvar = self._save_var_list["meta"][_val]["varname"]
337
+
338
+ # safety check, if None, replace with name of key (_val)
339
+ if _modelvar is None:
340
+ _modelvar = _val
341
+
315
342
  # use knowledge of time-varying values to save them
316
- if self._save_var_list["meta"][_val][0] is None:
317
- self.output_netcdf["meta"][_val][save_idx] = getattr(self, _val)
343
+ if _dims > 2:
344
+ self.output_netcdf[self._subgroup_name][_ncvar][save_idx] = getattr(
345
+ self, _modelvar
346
+ )
347
+ else:
348
+ pass # do not re-save values that do not change over time
318
349
 
319
350
  # -------------------- sync --------------------
320
351
  if self._save_metadata or self._save_any_grids: