igm-model 2.1.0__tar.gz → 2.2.1__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 (140) hide show
  1. {igm-model-2.1.0/igm_model.egg-info → igm-model-2.2.1}/PKG-INFO +12 -8
  2. {igm-model-2.1.0 → igm-model-2.2.1}/README.md +8 -4
  3. igm-model-2.2.1/igm/__init__.py +28 -0
  4. igm-model-2.2.1/igm/common.py +380 -0
  5. igm-model-2.2.1/igm/igm_run.py +47 -0
  6. {igm-model-2.1.0 → igm-model-2.2.1}/igm/instructed_oggm.py +12 -4
  7. {igm-model-2.1.0/igm/modules/preproc → igm-model-2.2.1/igm/modules}/__init__.py +6 -0
  8. igm-model-2.2.1/igm/modules/postproc/anim_mayavi/__init__.py +6 -0
  9. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/anim_mayavi}/anim_mayavi.py +8 -13
  10. igm-model-2.2.1/igm/modules/postproc/anim_plotly/__init__.py +6 -0
  11. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/anim_plotly}/anim_plotly.py +27 -26
  12. igm-model-2.2.1/igm/modules/postproc/anim_video/__init__.py +6 -0
  13. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/anim_video}/anim_video.py +8 -14
  14. igm-model-2.2.1/igm/modules/postproc/plot2d/__init__.py +6 -0
  15. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/plot2d}/plot2d.py +6 -13
  16. igm-model-2.2.1/igm/modules/postproc/print_comp/__init__.py +6 -0
  17. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/print_comp}/print_comp.py +12 -29
  18. igm-model-2.2.1/igm/modules/postproc/print_info/__init__.py +6 -0
  19. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/print_info}/print_info.py +4 -4
  20. igm-model-2.2.1/igm/modules/postproc/write_ncdf/__init__.py +6 -0
  21. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/write_ncdf}/write_ncdf.py +10 -22
  22. igm-model-2.2.1/igm/modules/postproc/write_particles/__init__.py +6 -0
  23. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/write_particles}/write_particles.py +10 -16
  24. igm-model-2.2.1/igm/modules/postproc/write_tif/__init__.py +6 -0
  25. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/write_tif}/write_tif.py +5 -7
  26. igm-model-2.2.1/igm/modules/postproc/write_ts/__init__.py +6 -0
  27. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/postproc/write_ts}/write_ts.py +8 -22
  28. igm-model-2.2.1/igm/modules/preproc/__init__.py +24 -0
  29. igm-model-2.2.1/igm/modules/preproc/include_icemask/__init__.py +6 -0
  30. {igm-model-2.1.0/igm/modules/preproc → igm-model-2.2.1/igm/modules/preproc/include_icemask}/include_icemask.py +4 -4
  31. igm-model-2.2.1/igm/modules/preproc/infersmb.py +44 -0
  32. igm-model-2.2.1/igm/modules/preproc/load_ncdf/__init__.py +6 -0
  33. {igm-model-2.1.0/igm/modules/preproc → igm-model-2.2.1/igm/modules/preproc/load_ncdf}/load_ncdf.py +6 -6
  34. igm-model-2.2.1/igm/modules/preproc/load_tif/__init__.py +6 -0
  35. {igm-model-2.1.0/igm/modules/preproc → igm-model-2.2.1/igm/modules/preproc/load_tif}/load_tif.py +5 -5
  36. igm-model-2.2.1/igm/modules/preproc/oggm_shop/__init__.py +6 -0
  37. {igm-model-2.1.0/igm/modules/preproc → igm-model-2.2.1/igm/modules/preproc/oggm_shop}/oggm_shop.py +62 -28
  38. igm-model-2.2.1/igm/modules/preproc/optimize/__init__.py +8 -0
  39. {igm-model-2.1.0/igm/modules/preproc → igm-model-2.2.1/igm/modules/preproc/optimize}/optimize.py +186 -114
  40. igm-model-2.2.1/igm/modules/preproc/optimize_v1/__init__.py +6 -0
  41. {igm-model-2.1.0/igm/modules/preproc → igm-model-2.2.1/igm/modules/preproc/optimize_v1}/optimize_v1.py +12 -6
  42. igm-model-2.2.1/igm/modules/preproc/pretraining/__init__.py +6 -0
  43. {igm-model-2.1.0/igm/modules/preproc → igm-model-2.2.1/igm/modules/preproc/pretraining}/pretraining.py +22 -22
  44. {igm-model-2.1.0/igm/modules/postproc → igm-model-2.2.1/igm/modules/process}/__init__.py +2 -0
  45. igm-model-2.2.1/igm/modules/process/clim_oggm/__init__.py +6 -0
  46. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/clim_oggm}/clim_oggm.py +7 -6
  47. igm-model-2.2.1/igm/modules/process/flow_dt_thk/__init__.py +6 -0
  48. igm-model-2.2.1/igm/modules/process/flow_dt_thk/flow_dt_thk.py +32 -0
  49. igm-model-2.2.1/igm/modules/process/glerosion/__init__.py +6 -0
  50. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/glerosion}/glerosion.py +4 -4
  51. igm-model-2.2.1/igm/modules/process/iceflow/__init__.py +6 -0
  52. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/iceflow}/iceflow.py +243 -53
  53. igm-model-2.2.1/igm/modules/process/iceflow_v1/__init__.py +6 -0
  54. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/iceflow_v1}/iceflow_v1.py +4 -4
  55. igm-model-2.2.1/igm/modules/process/particles/__init__.py +6 -0
  56. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/particles}/particles.py +7 -6
  57. igm-model-2.2.1/igm/modules/process/particles_v1/__init__.py +6 -0
  58. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/particles_v1}/particles_v1.py +4 -4
  59. igm-model-2.2.1/igm/modules/process/read_output.py +99 -0
  60. igm-model-2.2.1/igm/modules/process/rockflow/__init__.py +6 -0
  61. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/rockflow}/rockflow.py +4 -4
  62. igm-model-2.2.1/igm/modules/process/smb_oggm/__init__.py +6 -0
  63. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/smb_oggm}/smb_oggm.py +4 -4
  64. igm-model-2.2.1/igm/modules/process/smb_simple/__init__.py +6 -0
  65. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/smb_simple}/smb_simple.py +5 -5
  66. igm-model-2.2.1/igm/modules/process/thk/__init__.py +6 -0
  67. igm-model-2.2.1/igm/modules/process/thk/thk.py +73 -0
  68. igm-model-2.2.1/igm/modules/process/time/__init__.py +6 -0
  69. {igm-model-2.1.0/igm/modules/process → igm-model-2.2.1/igm/modules/process/time}/time.py +4 -4
  70. igm-model-2.2.1/igm/modules/process/vert_flow/__init__.py +6 -0
  71. igm-model-2.2.1/igm/modules/process/vert_flow/vert_flow.py +146 -0
  72. {igm-model-2.1.0 → igm-model-2.2.1}/igm/modules/utils.py +85 -17
  73. {igm-model-2.1.0 → igm-model-2.2.1/igm_model.egg-info}/PKG-INFO +12 -8
  74. igm-model-2.2.1/igm_model.egg-info/SOURCES.txt +125 -0
  75. {igm-model-2.1.0 → igm-model-2.2.1}/igm_model.egg-info/requires.txt +2 -2
  76. igm-model-2.2.1/igm_model.egg-info/top_level.txt +2 -0
  77. igm-model-2.2.1/setup.py +47 -0
  78. igm-model-2.2.1/tests/__init__.py +3 -0
  79. igm-model-2.2.1/tests/test_modules/__init__.py +2 -0
  80. igm-model-2.2.1/tests/test_modules/invalid_custom_module_folder/__init__.py +6 -0
  81. igm-model-2.2.1/tests/test_modules/invalid_custom_module_folder/invalid_custom_module.py +27 -0
  82. igm-model-2.2.1/tests/test_modules/missing_function_custom_module.py +28 -0
  83. igm-model-2.2.1/tests/test_modules/test_loading_modules.py +24 -0
  84. igm-model-2.2.1/tests/test_modules/valid_custom_module.py +27 -0
  85. igm-model-2.2.1/tests/test_modules/valid_custom_module_folder/__init__.py +6 -0
  86. igm-model-2.2.1/tests/test_modules/valid_custom_module_folder/valid_custom_module.py +27 -0
  87. igm-model-2.2.1/tests/test_params/__init__.py +0 -0
  88. igm-model-2.2.1/tests/test_params/test_params.py +183 -0
  89. igm-model-2.1.0/igm/__init__.py +0 -44
  90. igm-model-2.1.0/igm/common.py +0 -187
  91. igm-model-2.1.0/igm/igm_run.py +0 -72
  92. igm-model-2.1.0/igm/modules/process/__init__.py +0 -4
  93. igm-model-2.1.0/igm/modules/process/avalanche.py +0 -124
  94. igm-model-2.1.0/igm/modules/process/enthalpy.py +0 -749
  95. igm-model-2.1.0/igm/modules/process/flow_dt_thk.py +0 -32
  96. igm-model-2.1.0/igm/modules/process/gflex.py +0 -80
  97. igm-model-2.1.0/igm/modules/process/thk.py +0 -55
  98. igm-model-2.1.0/igm/modules/process/vert_flow.py +0 -77
  99. igm-model-2.1.0/igm_model.egg-info/SOURCES.txt +0 -85
  100. igm-model-2.1.0/igm_model.egg-info/top_level.txt +0 -1
  101. igm-model-2.1.0/setup.py +0 -48
  102. {igm-model-2.1.0 → igm-model-2.2.1}/LICENSE +0 -0
  103. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/100/fieldin.dat +0 -0
  104. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/100/fieldout.dat +0 -0
  105. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/100/model.h5 +0 -0
  106. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/200/fieldin.dat +0 -0
  107. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/200/fieldout.dat +0 -0
  108. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/200/model.h5 +0 -0
  109. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/50/fieldin.dat +0 -0
  110. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/50/fieldout.dat +0 -0
  111. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/50/model.h5 +0 -0
  112. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/f15_cfsflow_GJ_22_a/README.md +0 -0
  113. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_16_3_1/fieldin.dat +0 -0
  114. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_16_3_1/fieldout.dat +0 -0
  115. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_16_3_1/model.h5 +0 -0
  116. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_2_0/fieldin.dat +0 -0
  117. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_2_0/fieldout.dat +0 -0
  118. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_2_0/model.h5 +0 -0
  119. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_2_1/fieldin.dat +0 -0
  120. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_2_1/fieldout.dat +0 -0
  121. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_2_1/model.h5 +0 -0
  122. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_3_0/fieldin.dat +0 -0
  123. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_3_0/fieldout.dat +0 -0
  124. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_3_0/model.h5 +0 -0
  125. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_3_1/fieldin.dat +0 -0
  126. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_3_1/fieldout.dat +0 -0
  127. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_16_32_3_1/model.h5 +0 -0
  128. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_8_32_2_0/fieldin.dat +0 -0
  129. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_8_32_2_0/fieldout.dat +0 -0
  130. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_8_32_2_0/model.h5 +0 -0
  131. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_8_32_2_1/fieldin.dat +0 -0
  132. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_8_32_2_1/fieldout.dat +0 -0
  133. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_10_4_cnn_8_32_2_1/model.h5 +0 -0
  134. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_30_4_cnn_12_32_3_1/fieldin.dat +0 -0
  135. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_30_4_cnn_12_32_3_1/fieldout.dat +0 -0
  136. {igm-model-2.1.0 → igm-model-2.2.1}/igm/emulators/pinnbp_30_4_cnn_12_32_3_1/model.h5 +0 -0
  137. {igm-model-2.1.0/igm/modules → igm-model-2.2.1/igm/modules/postproc}/__init__.py +0 -0
  138. {igm-model-2.1.0 → igm-model-2.2.1}/igm_model.egg-info/dependency_links.txt +0 -0
  139. {igm-model-2.1.0 → igm-model-2.2.1}/igm_model.egg-info/entry_points.txt +0 -0
  140. {igm-model-2.1.0 → igm-model-2.2.1}/setup.cfg +0 -0
@@ -1,44 +1,49 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: igm-model
3
- Version: 2.1.0
3
+ Version: 2.2.1
4
4
  Summary: IGM - a glacier evolution model
5
5
  Home-page: https://github.com/jouvetg/igm
6
6
  Author: Guillaume Jouvet
7
7
  Author-email: guillaume.jouvet@unil.ch
8
8
  License: gpl-3.0
9
- Requires-Python: <3.12
9
+ Requires-Python: <3.11
10
10
  Description-Content-Type: text/markdown
11
11
  License-File: LICENSE
12
+ Requires-Dist: tensorflow[and-cuda]==2.14.0
12
13
  Requires-Dist: matplotlib
13
- Requires-Dist: numpy
14
14
  Requires-Dist: scipy
15
- Requires-Dist: tensorflow==2.12.0
16
15
  Requires-Dist: netCDF4
17
16
  Requires-Dist: xarray
18
17
  Requires-Dist: rasterio
19
18
  Requires-Dist: pyproj
20
19
  Requires-Dist: geopandas
21
20
  Requires-Dist: oggm
21
+ Requires-Dist: salem
22
22
  Requires-Dist: importlib_resources
23
23
 
24
24
  [![License badge](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
25
25
  ### <h1 align="center" id="title">The Instructed Glacier Model (IGM) </h1>
26
+
27
+ <div align="center">
28
+ <img src="logo/logo_igm.svg" width="40%" alt="Alt text">
29
+ </div>
30
+
26
31
 
27
32
  # Overview
28
33
 
29
34
  The Instructed Glacier Model (IGM) is an **open-source Python package**, which permits to simulate **3D glacier evolution** accounting for the coupling between ice thermo-dynamics, surface mass balance, and mass conservation. IGM features:
30
35
 
31
- - **Simplicity and modularity:** IGM is implemented in the most popular programming language -- Python -- at a low level of abstractivity. IGM is organized **module-wise** for clarity and to facilitate coupling, customization and commmunity development. For simplicity, IGM assumes a horizontal regular grid for numerical discretization and therefore deals with **2D gridded input and output data**.
36
+ - **Accessibility and modularity:** IGM is implemented in the most popular programming language -- Python -- and takes large benefit of existing tools such as [OGGM](https://oggm.org/). It is organized **module-wise** to facilitate coupling, customization and commmunity development. For simplicity, IGM uses a horizontal regular grid for numerical discretization and therefore deals with **2D gridded input and output data**.
32
37
 
33
38
  - **State-of-the-art physics:** IGM implements mass conservation, **high-order** 3D ice flow mechanics, an **Enthalpy** model for the thermic regime of ice, **melt/accumulation surface mass balance** model, and other glaciological processes.
34
39
 
35
- - **Computational high efficiency:** Thanks to the **TensorFlow library**, mathematical operations are **fully-vectorized**. This permits tremendous **speed-ups on GPU**. **Physics-informed deep learning** is used as an alternative to numerical solvers for modelling ice flow physics in a vectorized way. While GPU are highly-recommended for modelling large domain / high resolution, IGM runs fairly well on CPU for individual glaciers.
40
+ - **Computational efficiency:** Thanks to the **TensorFlow library**, mathematical operations are **fully-vectorized**. This permits tremendous **speed-ups on GPU**. **Physics-informed deep learning** is used as an alternative to numerical solvers for modelling ice flow physics in a vectorized way. While GPU are highly-recommended for modelling large domain / high resolution, IGM runs fairly well on CPU for individual glaciers.
36
41
 
37
42
  - **Automatic differentiation:** TensorFlow operations are differentiable. Therefore, automatic differentiation strongly facilitates and speeds-up inverse modelling / data assimilation.
38
43
 
39
44
  # Documentation
40
45
 
41
- Start with the 10-min [video tutorial](https://vimeo.com/884003820). Then, all the documentation can be found on the dedicated [wiki](https://github.com/jouvetg/igm/wiki) and the the in-progress [concept paper](https://github.com/jouvetg/igm/blob/main/paper/paper.pdf).
46
+ Start with the 10-min [video tutorial](https://vimeo.com/884003820). Then, all the documentation can be found on the dedicated [wiki](https://github.com/jouvetg/igm/wiki) and the the in-progress and open-to-contributions [technical paper](https://github.com/jouvetg/igm-paper/paper.pdf).
42
47
 
43
48
  # Discord channel
44
49
 
@@ -47,4 +52,3 @@ IGM has a [discord channel](https://discord.com/) for quick support, getting lat
47
52
  # Contact
48
53
 
49
54
  Feel free to drop me an email for any questions, bug reports, or ideas of model extension: guillaume.jouvet at unil.ch
50
-
@@ -1,21 +1,26 @@
1
1
  [![License badge](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
2
2
  ### <h1 align="center" id="title">The Instructed Glacier Model (IGM) </h1>
3
+
4
+ <div align="center">
5
+ <img src="logo/logo_igm.svg" width="40%" alt="Alt text">
6
+ </div>
7
+
3
8
 
4
9
  # Overview
5
10
 
6
11
  The Instructed Glacier Model (IGM) is an **open-source Python package**, which permits to simulate **3D glacier evolution** accounting for the coupling between ice thermo-dynamics, surface mass balance, and mass conservation. IGM features:
7
12
 
8
- - **Simplicity and modularity:** IGM is implemented in the most popular programming language -- Python -- at a low level of abstractivity. IGM is organized **module-wise** for clarity and to facilitate coupling, customization and commmunity development. For simplicity, IGM assumes a horizontal regular grid for numerical discretization and therefore deals with **2D gridded input and output data**.
13
+ - **Accessibility and modularity:** IGM is implemented in the most popular programming language -- Python -- and takes large benefit of existing tools such as [OGGM](https://oggm.org/). It is organized **module-wise** to facilitate coupling, customization and commmunity development. For simplicity, IGM uses a horizontal regular grid for numerical discretization and therefore deals with **2D gridded input and output data**.
9
14
 
10
15
  - **State-of-the-art physics:** IGM implements mass conservation, **high-order** 3D ice flow mechanics, an **Enthalpy** model for the thermic regime of ice, **melt/accumulation surface mass balance** model, and other glaciological processes.
11
16
 
12
- - **Computational high efficiency:** Thanks to the **TensorFlow library**, mathematical operations are **fully-vectorized**. This permits tremendous **speed-ups on GPU**. **Physics-informed deep learning** is used as an alternative to numerical solvers for modelling ice flow physics in a vectorized way. While GPU are highly-recommended for modelling large domain / high resolution, IGM runs fairly well on CPU for individual glaciers.
17
+ - **Computational efficiency:** Thanks to the **TensorFlow library**, mathematical operations are **fully-vectorized**. This permits tremendous **speed-ups on GPU**. **Physics-informed deep learning** is used as an alternative to numerical solvers for modelling ice flow physics in a vectorized way. While GPU are highly-recommended for modelling large domain / high resolution, IGM runs fairly well on CPU for individual glaciers.
13
18
 
14
19
  - **Automatic differentiation:** TensorFlow operations are differentiable. Therefore, automatic differentiation strongly facilitates and speeds-up inverse modelling / data assimilation.
15
20
 
16
21
  # Documentation
17
22
 
18
- Start with the 10-min [video tutorial](https://vimeo.com/884003820). Then, all the documentation can be found on the dedicated [wiki](https://github.com/jouvetg/igm/wiki) and the the in-progress [concept paper](https://github.com/jouvetg/igm/blob/main/paper/paper.pdf).
23
+ Start with the 10-min [video tutorial](https://vimeo.com/884003820). Then, all the documentation can be found on the dedicated [wiki](https://github.com/jouvetg/igm/wiki) and the the in-progress and open-to-contributions [technical paper](https://github.com/jouvetg/igm-paper/paper.pdf).
19
24
 
20
25
  # Discord channel
21
26
 
@@ -24,4 +29,3 @@ IGM has a [discord channel](https://discord.com/) for quick support, getting lat
24
29
  # Contact
25
30
 
26
31
  Feel free to drop me an email for any questions, bug reports, or ideas of model extension: guillaume.jouvet at unil.ch
27
-
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright (C) 2021-2023 Guillaume Jouvet <guillaume.jouvet@unil.ch>
4
+ # Published under the GNU GPL (Version 3), check at the LICENSE file
5
+
6
+ import sys
7
+ import os
8
+ sys.path.append(os.getcwd()) # I guess by default sys.path does not have cwd. not sure if this is the convention though...
9
+
10
+ from . import modules, emulators
11
+
12
+ from .common import (
13
+ State,
14
+ params_core,
15
+ load_modules,
16
+ add_logger,
17
+ print_params,
18
+ load_dependent_modules,
19
+ get_modules_list,
20
+ load_user_defined_params,
21
+ run_intializers,
22
+ run_processes,
23
+ run_finalizers,
24
+ setup_igm_modules,
25
+ setup_igm_params,
26
+ add_logger,
27
+ print_gpu_info
28
+ )
@@ -0,0 +1,380 @@
1
+ #!/usr/bin/env python3
2
+
3
+ """
4
+ Copyright (C) 2021-2023 Guillaume Jouvet <guillaume.jouvet@unil.ch>
5
+ Published under the GNU GPL (Version 3), check at the LICENSE file
6
+ """
7
+
8
+ import os, json
9
+ from json import JSONDecodeError
10
+ import importlib
11
+ import argparse
12
+ from argparse import ArgumentParser, Namespace
13
+ from pathlib import Path
14
+ from functools import partial
15
+ from typing import List, Any, Dict, Tuple
16
+ from types import ModuleType
17
+ import logging
18
+ import warnings
19
+
20
+ import tensorflow as tf
21
+
22
+ import igm
23
+
24
+ IGM_DESCRIPTION = r"""
25
+ ┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
26
+ │ Welcome to IGM! The Iceflow Glacier Model (IGM) is a modular, open-source, and user-friendly glacier model. │
27
+ │ It is designed to be used in a variety of applications, including glacier evolution, ice flow, and ice │
28
+ │ dynamics. │
29
+ │ │
30
+ │ __/\\\\\\\\\\\_____/\\\\\\\\\\\\__/\\\\____________/\\\\_ │
31
+ │ _\/////\\\///____/\\\//////////__\/\\\\\\________/\\\\\\_ │
32
+ │ _____\/\\\______/\\\_____________\/\\\//\\\____/\\\//\\\_ │
33
+ │ _____\/\\\_____\/\\\____/\\\\\\\_\/\\\\///\\\/\\\/_\/\\\_ │
34
+ │ _____\/\\\_____\/\\\___\/////\\\_\/\\\__\///\\\/___\/\\\_ │
35
+ │ _____\/\\\_____\/\\\_______\/\\\_\/\\\____\///_____\/\\\_ │
36
+ │ _____\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\_ │
37
+ │ __/\\\\\\\\\\\_\//\\\\\\\\\\\\/__\/\\\_____________\/\\\_ │
38
+ │ _\///////////___\////////////____\///______________\///__ │
39
+ └──────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
40
+ """
41
+
42
+
43
+ class State:
44
+ pass
45
+
46
+
47
+ # this create core parameters for any IGM run
48
+ def params_core() -> argparse.ArgumentParser:
49
+ parser = ArgumentParser(
50
+ description=IGM_DESCRIPTION,
51
+ formatter_class=argparse.RawDescriptionHelpFormatter,
52
+ conflict_handler="resolve",
53
+ ) # automatically overrides repeated/older parameters! Valid solution?
54
+
55
+ parser.add_argument(
56
+ "--param_file",
57
+ type=str,
58
+ default="params.json",
59
+ help="Path for the JSON parameter file. (default: %(default)s)",
60
+ )
61
+ parser.add_argument(
62
+ "--modules_preproc",
63
+ type=list,
64
+ default=["oggm_shop"],
65
+ help="List of pre-processing modules (default: %(default)s)",
66
+ )
67
+ parser.add_argument(
68
+ "--modules_process",
69
+ type=list,
70
+ default=["iceflow", "time", "thk"],
71
+ help="List of processing modules (default: %(default)s)",
72
+ )
73
+ parser.add_argument(
74
+ "--modules_postproc",
75
+ type=list,
76
+ default=["write_ncdf", "plot2d", "print_info"],
77
+ help="List of post-processing modules (default: %(default)s)",
78
+ )
79
+ parser.add_argument(
80
+ "--logging",
81
+ action="store_true",
82
+ default=False,
83
+ help="Activates the logging (default: %(default)s)",
84
+ )
85
+ parser.add_argument(
86
+ "--logging_level",
87
+ default=30,
88
+ type=int,
89
+ help="Determine logging level used for logger (default: %(default)s)",
90
+ )
91
+ parser.add_argument(
92
+ "--logging_file",
93
+ type=str,
94
+ default="",
95
+ help="Logging file name, if empty it prints in the screen (default: %(default)s)",
96
+ )
97
+ parser.add_argument(
98
+ "--print_params",
99
+ action="store_false",
100
+ default=True,
101
+ help="Print definitive parameters in a file for record (default: %(default)s)",
102
+ )
103
+ parser.add_argument(
104
+ "--gpu_info",
105
+ action="store_true",
106
+ default=False,
107
+ help="Print CUDA and GPU information to the screen (default: %(default)s)",
108
+ )
109
+ parser.add_argument(
110
+ "--gpu_id",
111
+ type=int,
112
+ default=0,
113
+ help="Id of the GPU to use (default: %(default)s)",
114
+ )
115
+ parser.add_argument(
116
+ "--saved_params_filename",
117
+ type=str,
118
+ default="params_saved",
119
+ help="Name of the file to store the parameters used in the run (default: %(default)s)",
120
+ )
121
+
122
+ return parser
123
+
124
+
125
+ def setup_igm_modules(params: Namespace) -> List[ModuleType]:
126
+
127
+ modules_dict = get_modules_list(params.param_file)
128
+ imported_modules = load_modules(modules_dict)
129
+ imported_modules = load_dependent_modules(imported_modules)
130
+
131
+ return imported_modules
132
+
133
+
134
+ def setup_igm_params(
135
+ parser: ArgumentParser, imported_modules: List[ModuleType]
136
+ ) -> Namespace:
137
+ for module in imported_modules:
138
+ module.params(parser)
139
+
140
+ core_and_module_params = parser.parse_args()
141
+ params = load_user_defined_params(
142
+ param_file=core_and_module_params.param_file,
143
+ params_dict=vars(core_and_module_params),
144
+ )
145
+
146
+ parser.set_defaults(**params)
147
+ params = parser.parse_args()
148
+
149
+ return params
150
+
151
+
152
+ def run_intializers(modules: List, params: Any, state: State) -> None:
153
+ for module in modules:
154
+ module.initialize(params, state)
155
+
156
+
157
+ def run_processes(modules: List, params: Any, state: State) -> None:
158
+ if hasattr(state, "t"):
159
+ while state.t < params.time_end:
160
+ for module in modules:
161
+ module.update(params, state)
162
+
163
+
164
+ def run_finalizers(modules: List, params: Any, state: State) -> None:
165
+ for module in modules:
166
+ module.finalize(params, state)
167
+
168
+
169
+ def add_logger(params, state) -> None:
170
+ if params.logging_file == "":
171
+ pathf = ""
172
+ else:
173
+ pathf = params.logging_file
174
+
175
+ logging.basicConfig(
176
+ filename=pathf,
177
+ encoding="utf-8",
178
+ filemode="w",
179
+ level=params.logging_level,
180
+ format="%(asctime)s - %(levelname)s - %(message)s",
181
+ )
182
+ logging.root.setLevel(params.logging_level)
183
+
184
+ state.logger = logging.getLogger("igm_logger")
185
+ if not pathf == "":
186
+ os.system("echo rm " + pathf + " >> clean.sh")
187
+
188
+
189
+ def remove_comments(json_str) -> str:
190
+ lines = json_str.split("\n")
191
+ cleaned_lines = [
192
+ line for line in lines if not line.strip().startswith(("//", "#"))
193
+ ] # ! TODO: Add blocks comments...
194
+ cleaned_text = "\n".join(cleaned_lines)
195
+ return cleaned_text
196
+
197
+
198
+ def load_json_file(
199
+ param_file: str, remove_param_comments: bool = True
200
+ ) -> Dict[str, Any]:
201
+ with open(param_file, "r") as json_file:
202
+ json_text = json_file.read()
203
+
204
+ if remove_param_comments:
205
+ json_text = remove_comments(json_text)
206
+
207
+ dic_params = json.loads(json_text)
208
+ return dic_params
209
+
210
+
211
+ def get_modules_list(params_path: str) -> dict[str, List[str]]:
212
+ try:
213
+ with open(params_path) as f:
214
+ # params_dict = json.load(f) #re-instate if you want to enforce no comments in the json file(remove all the lines that load the clean json in this case...)
215
+ json_text = f.read()
216
+ json_cleaned = remove_comments(json_text)
217
+ params_dict = json.loads(json_cleaned)
218
+ module_dict = {
219
+ "modules_preproc": params_dict["modules_preproc"],
220
+ "modules_process": params_dict["modules_process"],
221
+ "modules_postproc": params_dict["modules_postproc"],
222
+ }
223
+
224
+ return module_dict
225
+ except JSONDecodeError as e:
226
+ raise JSONDecodeError(
227
+ msg="For the following line, please check the 1) JSON file structure and/or 2) make sure there are no comments (//, #, etc.)",
228
+ doc=e.doc,
229
+ pos=e.pos,
230
+ )
231
+
232
+
233
+ def load_user_defined_params(param_file: str, params_dict: dict[str, Any]):
234
+ try:
235
+ json_defined_params = load_json_file(param_file=param_file)
236
+ except JSONDecodeError as e:
237
+ raise JSONDecodeError(
238
+ msg=f"Error decoding JSON: Please make sure your file path is correct or your json is properly formatted.",
239
+ doc=e.doc,
240
+ pos=e.pos,
241
+ )
242
+
243
+ unrecognized_json_arguments = {
244
+ k: v for k, v in json_defined_params.items() if k not in params_dict
245
+ }
246
+ params_dict.update(json_defined_params)
247
+
248
+ for key in unrecognized_json_arguments.keys():
249
+ raise ValueError(
250
+ f"The following argument specified in the JSON file does not exist among the core arguments nor the modules you have chosen: {key}"
251
+ )
252
+
253
+ return params_dict
254
+
255
+
256
+ def load_modules(modules_dict: Dict) -> List[ModuleType]:
257
+ """Returns a list of actionable modules to then apply the update, initialize, finalize functions on for IGM."""
258
+
259
+ imported_preproc_modules = load_modules_from_directory(
260
+ modules_list=modules_dict["modules_preproc"], module_folder="preproc"
261
+ )
262
+ imported_process_modules = load_modules_from_directory(
263
+ modules_list=modules_dict["modules_process"], module_folder="process"
264
+ )
265
+ imported_postproc_modules = load_modules_from_directory(
266
+ modules_list=modules_dict["modules_postproc"], module_folder="postproc"
267
+ )
268
+ # ? Should we have custom modules in a seperate folder?
269
+ # imported_custom_modules = load_modules_from_directory(
270
+ # modules_list=modules_dict.modules_custom, module_folder=params.modules_custom_folder
271
+ # )
272
+
273
+ return (
274
+ imported_preproc_modules
275
+ + imported_process_modules
276
+ + imported_postproc_modules # + imported_custom_modules
277
+ )
278
+
279
+
280
+ def validate_module(module) -> None:
281
+ """Validates that a module has the required functions to be used in IGM."""
282
+ required_functions = ["params", "initialize", "finalize", "update"]
283
+ for function in required_functions:
284
+ if not hasattr(module, function):
285
+ raise AttributeError(
286
+ f"Module {module} is missing the required function ({function}). If it is a custom python package, make sure to include the 4 required functions: ['params', 'initialize', 'finalize', 'update'].",
287
+ f"Please see https://github.com/jouvetg/igm/wiki/5.-Custom-modules-(coding) for more information on how to construct custom modules.",
288
+ )
289
+
290
+
291
+ def load_modules_from_directory(
292
+ modules_list: List[str], module_folder: str
293
+ ) -> List[ModuleType]:
294
+ imported_modules = []
295
+ for module_name in modules_list:
296
+ module_path = f"igm.modules.{module_folder}.{module_name}"
297
+ try:
298
+ module = importlib.import_module(module_path)
299
+ except ModuleNotFoundError:
300
+ logging.info(
301
+ f"Error importing module: {module_path}, checking for custom package in current working directory."
302
+ )
303
+ try:
304
+ logging.info(
305
+ f"Trying to import custom module from current working directory (folder or .py): {module_name}"
306
+ )
307
+ module = importlib.import_module(module_name)
308
+ except ModuleNotFoundError:
309
+ raise ModuleNotFoundError(
310
+ f"Can not find module {module_name}. Make sure it is either in the 1) {Path(igm.__file__).parent}/modules/{module_folder} directory or 2) in your current working directory."
311
+ )
312
+
313
+ validate_module(module)
314
+ imported_modules.append(module)
315
+
316
+ return imported_modules
317
+
318
+
319
+ def has_dependencies(module: Any) -> bool:
320
+ if hasattr(module, "dependencies"):
321
+ return True
322
+ return False
323
+
324
+
325
+ def load_dependent_modules(imported_modules: List) -> List[ModuleType]:
326
+ imported_dependencies = set()
327
+ for module in imported_modules:
328
+ if has_dependencies(module):
329
+ module_dependencies = module.dependencies
330
+ directories_to_search = [
331
+ "preproc",
332
+ "process",
333
+ "postproc",
334
+ ] # will also check current working directory if any of them fail
335
+ load_modules_partial = partial(
336
+ load_modules_from_directory, module_dependencies
337
+ )
338
+ for directory in directories_to_search:
339
+ try:
340
+ dependent_module = load_modules_partial(module_folder=directory)
341
+ imported_dependencies.add(
342
+ dependent_module[0]
343
+ ) # [0] because it returns a singleton list
344
+ logging.info(
345
+ f"Found dependencies in directory {directory} or current working directory. Checking next module for dependencies."
346
+ )
347
+ break
348
+ except ModuleNotFoundError:
349
+ logging.info(
350
+ f"Could not find dependencies in directory {directory} or current working directory. Checking next IGM directory."
351
+ )
352
+
353
+ return imported_modules + list(imported_dependencies)
354
+
355
+
356
+ def print_gpu_info() -> None:
357
+ gpus = tf.config.experimental.list_physical_devices("GPU")
358
+ print(f"{'CUDA Enviroment':-^150}")
359
+ tf.sysconfig.get_build_info().pop("cuda_compute_capabilities", None)
360
+ print(f"{json.dumps(tf.sysconfig.get_build_info(), indent=2, default=str)}")
361
+ print(f"{'Available GPU Devices':-^150}")
362
+ for gpu in gpus:
363
+ gpu_info = {"gpu_id": gpu.name, "device_type": gpu.device_type}
364
+ device_details = tf.config.experimental.get_device_details(gpu)
365
+ gpu_info.update(device_details)
366
+
367
+ print(f"{json.dumps(gpu_info, indent=2, default=str)}")
368
+ print(f"{'':-^150}")
369
+
370
+
371
+ # Print parameters in screen and a dedicated file
372
+ def print_params(params: Namespace) -> None:
373
+ param_file = params.saved_params_filename
374
+ param_file = param_file + ".json"
375
+
376
+ # load the given parameters
377
+ with open(param_file, "w") as json_file:
378
+ json.dump(params.__dict__, json_file, indent=2)
379
+
380
+ os.system("echo rm " + param_file + " >> clean.sh")
@@ -0,0 +1,47 @@
1
+ #!/usr/bin/env python3
2
+
3
+ # Copyright (C) 2021-2023 Guillaume Jouvet <guillaume.jouvet@unil.ch>
4
+ # Published under the GNU GPL (Version 3), check at the LICENSE file
5
+
6
+ import tensorflow as tf
7
+ from igm import (
8
+ State,
9
+ params_core,
10
+ print_params,
11
+ run_intializers,
12
+ run_processes,
13
+ run_finalizers,
14
+ setup_igm_modules,
15
+ setup_igm_params,
16
+ print_gpu_info,
17
+ add_logger
18
+ )
19
+
20
+
21
+ def main() -> None:
22
+ state = State() # class acting as a dictionary
23
+ parser = params_core()
24
+ params, _ = parser.parse_known_args()
25
+
26
+ if params.gpu_info:
27
+ print_gpu_info()
28
+
29
+ if params.logging:
30
+ add_logger(params=params, state=state)
31
+ tf.get_logger().setLevel(params.logging_level)
32
+
33
+ imported_modules = setup_igm_modules(params)
34
+ params = setup_igm_params(parser, imported_modules)
35
+
36
+ if params.print_params:
37
+ print_params(params=params)
38
+
39
+ # Place the computation on your device GPU ('/GPU:0') or CPU ('/CPU:0')
40
+ with tf.device(f"/GPU:{params.gpu_id}"): # type: ignore for linting checks
41
+ run_intializers(imported_modules, params, state)
42
+ run_processes(imported_modules, params, state)
43
+ run_finalizers(imported_modules, params, state)
44
+
45
+
46
+ if __name__ == "__main__":
47
+ main()
@@ -76,8 +76,16 @@ class IGM_Model2D(Model2D):
76
76
 
77
77
  """
78
78
 
79
- parser = argparse.ArgumentParser(description="IGM")
80
- igm.params_iceflow(parser)
79
+ # parser = argparse.ArgumentParser(description="IGM")
80
+ parser = igm.params_core()
81
+
82
+ params, __ = parser.parse_known_args() # args=[] add this for jupyter notebook
83
+
84
+ imported_modules = igm.load_modules(params)
85
+
86
+ for module in imported_modules:
87
+ module.params(parser)
88
+
81
89
  self.params = parser.parse_args(args=[])
82
90
 
83
91
  self.state = igm.State()
@@ -111,7 +119,7 @@ class IGM_Model2D(Model2D):
111
119
 
112
120
  self.icemask = mb_filter
113
121
 
114
- igm.initialize_iceflow(self.params, self.state)
122
+ igm.modules.process.iceflow.initialize(self.params, self.state)
115
123
 
116
124
  def step(self, dt):
117
125
  # recast glacier variables into igm-like variables
@@ -120,7 +128,7 @@ class IGM_Model2D(Model2D):
120
128
  self.state.usurf.assign(self.surface_h)
121
129
 
122
130
  # compute ubar and vbar
123
- igm.update_iceflow(self.params, self.state)
131
+ igm.modules.process.iceflow.update(self.params, self.state)
124
132
 
125
133
  # retrurn the divergence of the flux using upwind fluxes
126
134
  divflux = (
@@ -2,3 +2,9 @@
2
2
 
3
3
  # Copyright (C) 2021-2023 Guillaume Jouvet <guillaume.jouvet@unil.ch>
4
4
  # Published under the GNU GPL (Version 3), check at the LICENSE file
5
+
6
+ from . import (
7
+ preproc,
8
+ process,
9
+ postproc,
10
+ )
@@ -0,0 +1,6 @@
1
+ from .anim_mayavi import (
2
+ params,
3
+ initialize,
4
+ finalize,
5
+ update
6
+ )
@@ -3,26 +3,23 @@
3
3
  # Copyright (C) 2021-2023 Guillaume Jouvet <guillaume.jouvet@unil.ch>
4
4
  # Published under the GNU GPL (Version 3), check at the LICENSE file
5
5
 
6
- import numpy as np
7
- import os, sys, shutil
8
- import time
9
6
  import tensorflow as tf
10
7
  import matplotlib.pyplot as plt
11
8
 
12
9
 
13
- def params_anim_mayavi(parser):
10
+ def params(parser):
14
11
  pass
15
12
 
16
13
 
17
- def initialize_anim_mayavi(params, state):
14
+ def initialize(params, state):
18
15
  pass
19
16
 
20
17
 
21
- def update_anim_mayavi(params, state):
18
+ def update(params, state):
22
19
  pass
23
20
 
24
21
 
25
- def finalize_anim_mayavi(params, state):
22
+ def finalize(params, state):
26
23
  from mayavi import mlab
27
24
  import xarray as xr
28
25
  import numpy as np
@@ -30,9 +27,7 @@ def finalize_anim_mayavi(params, state):
30
27
 
31
28
  plt.close("all")
32
29
 
33
- ds = xr.open_dataset(
34
- os.path.join(params.working_dir, "output.nc"), engine="netcdf4"
35
- )
30
+ ds = xr.open_dataset("output.nc", engine="netcdf4")
36
31
 
37
32
  X, Y = np.meshgrid(ds.x, ds.y)
38
33
 
@@ -57,7 +52,7 @@ def finalize_anim_mayavi(params, state):
57
52
 
58
53
  VEC = hasattr(ds, "uvelsurf") & hasattr(ds, "vvelsurf") & hasattr(ds, "wvelsurf")
59
54
 
60
- PAR = os.path.isdir(os.path.join(params.working_dir, "trajectories"))
55
+ PAR = os.path.isdir("trajectories")
61
56
 
62
57
  if VEC:
63
58
  quiv = mlab.quiver3d(
@@ -70,7 +65,7 @@ def finalize_anim_mayavi(params, state):
70
65
  )
71
66
 
72
67
  # if PAR:
73
- # f = os.path.join(params.working_dir, "trajectories",'traj-'+"{:06.0f}".format(TIME[0])+".csv")
68
+ # f = os.path.join("trajectories",'traj-'+"{:06.0f}".format(TIME[0])+".csv")
74
69
  # XYZ = np.loadtxt(f,skiprows=1,delimiter=',')
75
70
  # pt3d = mlab.points3d(XYZ[:,1], XYZ[:,2], XYZ[:,3], colormap="RdBu",mode='point')
76
71
  # pt3d.actor.property.point_size = 5
@@ -87,7 +82,7 @@ def finalize_anim_mayavi(params, state):
87
82
  quiv.mlab_source.v = np.array(tf.expand_dims(ds.vvelsurf[i], axis=0))
88
83
  quiv.mlab_source.w = np.array(tf.expand_dims(ds.wvelsurf[i], axis=0))
89
84
  # if PAR:
90
- # f = os.path.join(params.working_dir, "trajectories",'traj-'+"{:06.0f}".format(TIME[i])+".csv")
85
+ # f = os.path.join("trajectories",'traj-'+"{:06.0f}".format(TIME[i])+".csv")
91
86
  # XYZ = np.loadtxt(f,skiprows=1,delimiter=',')
92
87
  # pt3d.mlab_source.x = XYZ[:,1]
93
88
  # pt3d.mlab_source.y = XYZ[:,2]