tilupy 0.1.3__tar.gz → 0.1.5__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.

Potentially problematic release.


This version of tilupy might be problematic. Click here for more details.

Files changed (37) hide show
  1. {tilupy-0.1.3/src/tilupy.egg-info → tilupy-0.1.5}/PKG-INFO +11 -4
  2. {tilupy-0.1.3 → tilupy-0.1.5}/README.md +1 -1
  3. {tilupy-0.1.3 → tilupy-0.1.5}/pyproject.toml +3 -3
  4. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/calibration.py +29 -32
  5. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/cmd.py +30 -26
  6. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/initdata.py +36 -0
  7. tilupy-0.1.5/src/tilupy/make_mass.py +108 -0
  8. tilupy-0.1.5/src/tilupy/make_topo.py +415 -0
  9. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/models/shaltop/initsimus.py +8 -7
  10. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/plot.py +48 -4
  11. {tilupy-0.1.3 → tilupy-0.1.5/src/tilupy.egg-info}/PKG-INFO +11 -4
  12. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy.egg-info/SOURCES.txt +3 -0
  13. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy.egg-info/requires.txt +1 -0
  14. tilupy-0.1.5/tests/test_generated_data.py +17 -0
  15. tilupy-0.1.5/tests/test_shaltop.py +106 -0
  16. tilupy-0.1.3/tests/test_shaltop.py +0 -66
  17. {tilupy-0.1.3 → tilupy-0.1.5}/LICENSE +0 -0
  18. {tilupy-0.1.3 → tilupy-0.1.5}/MANIFEST.in +0 -0
  19. {tilupy-0.1.3 → tilupy-0.1.5}/data/frankslide/rasters/Frankslide_pile.asc +0 -0
  20. {tilupy-0.1.3 → tilupy-0.1.5}/data/frankslide/rasters/Frankslide_topography.asc +0 -0
  21. {tilupy-0.1.3 → tilupy-0.1.5}/setup.cfg +0 -0
  22. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/__init__.py +0 -0
  23. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/compare.py +0 -0
  24. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/download_data.py +0 -0
  25. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/models/__init__.py +0 -0
  26. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/models/ravaflow/__init__.py +0 -0
  27. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/models/ravaflow/initsimus.py +0 -0
  28. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/models/ravaflow/read.py +0 -0
  29. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/models/shaltop/__init__.py +0 -0
  30. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/models/shaltop/read.py +0 -0
  31. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/notations.py +0 -0
  32. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/raster.py +0 -0
  33. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/read.py +0 -0
  34. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy/utils.py +0 -0
  35. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy.egg-info/dependency_links.txt +0 -0
  36. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy.egg-info/entry_points.txt +0 -0
  37. {tilupy-0.1.3 → tilupy-0.1.5}/src/tilupy.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tilupy
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: Thin-layer models unified processing tool
5
5
  Author-email: Marc Peruzzetto <m.peruzzetto@brgm.fr>
6
6
  License: CeCILL-C FREE SOFTWARE LICENSE AGREEMENT
@@ -524,12 +524,19 @@ Keywords: thin-layer,shallow-water,display,simulation,model,processing,benchmark
524
524
  Classifier: License :: CeCILL-C Free Software License Agreement (CECILL-C)
525
525
  Classifier: Programming Language :: Python
526
526
  Classifier: Programming Language :: Python :: 3
527
- Requires-Python: >=3.10
527
+ Requires-Python: >=3.8
528
528
  Description-Content-Type: text/markdown
529
+ License-File: LICENSE
530
+ Requires-Dist: seaborn
531
+ Requires-Dist: requests
532
+ Requires-Dist: scipy
529
533
  Provides-Extra: test
534
+ Requires-Dist: pytest; extra == "test"
530
535
  Provides-Extra: dev
536
+ Requires-Dist: pipreqs; extra == "dev"
531
537
  Provides-Extra: gis
532
- License-File: LICENSE
538
+ Requires-Dist: rasterio; extra == "gis"
539
+ Requires-Dist: shapely; extra == "gis"
533
540
 
534
541
  # tilupy
535
542
 
@@ -553,7 +560,7 @@ It contains one submodule per thin-layer model for writing and reading raw input
553
560
  Outputs are then easily compared between different simulations / models. The models themselves are not part of this package and must
554
561
  be installed separately.
555
562
 
556
- Note that `tilupy` is still under development, thus only minimal documentation is available at the moment and testing is underway.
563
+ Note that `tilupy` is still under development, thus only minimal documentation is available at the moment, and testing is underway.
557
564
  Contributions are feedback are most welcome. Reading and writing is available for the `SHALTOP` model (most commonly used by the author) and `r.avaflow`
558
565
  (only partly maintained).
559
566
 
@@ -20,7 +20,7 @@ It contains one submodule per thin-layer model for writing and reading raw input
20
20
  Outputs are then easily compared between different simulations / models. The models themselves are not part of this package and must
21
21
  be installed separately.
22
22
 
23
- Note that `tilupy` is still under development, thus only minimal documentation is available at the moment and testing is underway.
23
+ Note that `tilupy` is still under development, thus only minimal documentation is available at the moment, and testing is underway.
24
24
  Contributions are feedback are most welcome. Reading and writing is available for the `SHALTOP` model (most commonly used by the author) and `r.avaflow`
25
25
  (only partly maintained).
26
26
 
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "tilupy"
9
- version = "0.1.3"
9
+ version = "0.1.5"
10
10
  description = "Thin-layer models unified processing tool"
11
11
  readme = "README.md"
12
12
  authors = [{ name = "Marc Peruzzetto", email = "m.peruzzetto@brgm.fr" }]
@@ -18,9 +18,9 @@ classifiers = [
18
18
  ]
19
19
  keywords = ["thin-layer", "shallow-water", "display", "simulation", "model", "processing", "benchmark"]
20
20
  dependencies = [
21
- "seaborn", "requests",
21
+ "seaborn", "requests", "scipy"
22
22
  ]
23
- requires-python = ">=3.10"
23
+ requires-python = ">=3.8"
24
24
 
25
25
  [project.optional-dependencies]
26
26
  test = ["pytest"]
@@ -10,51 +10,54 @@ import pandas as pd
10
10
 
11
11
  from tilupy import read
12
12
  from tilupy import utils
13
- from tilupy import dem
13
+ from tilupy import raster
14
+
14
15
 
15
16
  def CSI(simu, observation=None, h_threshs=[1], state='h_final'):
16
-
17
- res=[]
17
+
18
+ res = []
18
19
  assert(observation is not None)
19
-
20
+
20
21
  if isinstance(observation, str):
21
- _, _, observation, _ = dem.read_raster(observation)
22
-
22
+ _, _, observation, _ = raster.read_raster(observation)
23
+
23
24
  strs = state.split('_')
24
25
  if state == 'h_max':
25
26
  d = simu.h_max
26
27
  else:
27
28
  d = simu.get_static_output(strs[0], strs[1]).d
28
29
  for h_thresh in h_threshs:
29
- array = 1*d>h_thresh
30
+ array = 1*d > h_thresh
30
31
  res.append(utils.CSI(array, observation))
31
-
32
+
32
33
  return h_threshs, res
33
-
34
+
35
+
34
36
  def diff_runout(simu, point=None, h_threshs=[1],
35
37
  section=None, orientation='W-E',
36
38
  state='h_max',
37
39
  get_contour_kws=None):
38
-
40
+
39
41
  res = []
40
42
  assert(point is not None)
41
-
43
+
42
44
  if get_contour_kws is None:
43
45
  get_contour_kws = dict()
44
-
46
+
45
47
  if state == 'h_max':
46
- d=simu.h_max
48
+ d = simu.h_max
47
49
  else:
48
50
  strs = state.split('_')
49
51
  d = simu.get_static_output(strs[0], strs[1]).d
50
- xc, yc = utils.get_contour(simu.x,simu.y,d,h_threshs, **get_contour_kws)
51
-
52
+ xc, yc = utils.get_contour(simu.x, simu.y, d, h_threshs, **get_contour_kws)
53
+
52
54
  for h in h_threshs:
53
55
  res.append(utils.diff_runout(xc[h], yc[h], point, section=section,
54
56
  orientation=orientation))
55
-
57
+
56
58
  return h_threshs, res
57
-
59
+
60
+
58
61
  def eval_simus(simus, methods, calib_parameters, methods_kws,
59
62
  code='shaltop',
60
63
  recorded_params=['delta1'],
@@ -80,16 +83,17 @@ def eval_simus(simus, methods, calib_parameters, methods_kws,
80
83
  methods_kws = [methods_kws]
81
84
 
82
85
  if isinstance(simus, dict):
83
- simus=pd.DataFrame(simus)
86
+ simus = pd.DataFrame(simus)
84
87
  if isinstance(simus, pd.DataFrame):
85
88
  simus_list = []
86
89
  for i in range(simus.shape[0]):
87
- simus_list.append(read.get_results(code, **simus.iloc[i, :].to_dict()))
90
+ simus_list.append(read.get_results(
91
+ code, **simus.iloc[i, :].to_dict()))
88
92
  simus2 = simus.copy()
89
93
  else:
90
94
  simus_list = simus
91
95
  simus2 = pd.DataFrame()
92
-
96
+
93
97
  for param in recorded_params:
94
98
  simus2[param] = np.nan
95
99
  fn = dict()
@@ -97,13 +101,13 @@ def eval_simus(simus, methods, calib_parameters, methods_kws,
97
101
  fn[method] = globals()[method]
98
102
  simus2[method] = np.nan
99
103
  simus2[calib_parameter_name] = np.nan
100
-
104
+
101
105
  ns = len(simus_list)
102
106
  nc = len(calib_parameters)
103
107
  nn = ns*nc
104
-
105
- res = pd.DataFrame(columns=simus2.columns, index=np.arange(nn))
106
-
108
+
109
+ res = pd.DataFrame(columns=simus2.columns, index=np.arange(nn))
110
+
107
111
  for i, simu in enumerate(simus_list):
108
112
  # Initiate fields
109
113
  istart = i*nc
@@ -117,12 +121,5 @@ def eval_simus(simus, methods, calib_parameters, methods_kws,
117
121
  res.loc[:, param].iloc[istart:iend] = simu.params[param]
118
122
  res.loc[:, calib_parameter_name].iloc[istart:iend] = calib_parameters
119
123
  res.loc[:, method].iloc[istart:iend] = calib_res
120
-
121
- return res
122
124
 
123
-
124
-
125
-
126
-
127
-
128
-
125
+ return res
@@ -11,60 +11,63 @@ import tilupy.read
11
11
  import os
12
12
  import argparse
13
13
  import glob
14
-
14
+
15
15
 
16
16
  def process_results(fn_name, model, res_name, folder=None, param_files=None,
17
17
  kwargs_read=None, **kwargs_fn):
18
-
18
+
19
19
  assert(model is not None)
20
-
20
+
21
21
  if folder is None:
22
22
  folder = os.getcwd()
23
-
23
+
24
24
  if param_files is None:
25
25
  param_files = '*.txt'
26
-
26
+
27
27
  print(folder, param_files)
28
-
29
- param_files = glob.glob(param_files, root_dir=folder)
30
-
28
+
29
+ param_files = glob.glob(os.path.join(folder, param_files))
30
+
31
31
  if len(param_files) == 0:
32
32
  print('No parameter file matching param_files pattern was found')
33
33
  return
34
-
34
+
35
35
  if kwargs_read is None:
36
36
  kwargs_read = dict()
37
-
38
- kw_read = dict(folder_base=folder)
37
+
38
+ kw_read = dict(folder_base=folder)
39
39
  kw_read.update(kwargs_read)
40
-
40
+
41
41
  for param_file in param_files:
42
42
  print_str = 'Processing simulation {:s}, {:s} {:s} .....'
43
43
  print(print_str.format(param_file, fn_name, res_name))
44
44
  kw_read['file_params'] = param_file
45
45
  res = tilupy.read.get_results(model, **kw_read)
46
46
  getattr(res, fn_name)(res_name, **kwargs_fn)
47
-
48
- def to_raster(model=None, res_name='h', param_files=None, folder=None,
47
+
48
+
49
+ def to_raster(model=None, res_name='h', param_files=None, folder=None,
49
50
  kwargs_read=None, **kwargs):
50
-
51
+
51
52
  kw = dict(fmt='asc')
52
53
  kw.update(kwargs)
53
-
54
+
54
55
  process_results('save', model, res_name,
55
56
  folder=folder, param_files=param_files,
56
57
  kwargs_read=kwargs_read, **kw)
57
-
58
- def plot_results(model=None, res_name='h', param_files=None, folder=None,
58
+
59
+
60
+ def plot_results(model=None, res_name='h', param_files=None, folder=None,
59
61
  kwargs_read=None, **kwargs):
60
-
62
+
61
63
  kw = dict(save=True)
62
64
  kw.update(kwargs)
63
-
65
+
64
66
  process_results('plot', model, res_name,
65
67
  folder=folder, param_files=param_files,
66
68
  kwargs_read=kwargs_read, **kwargs)
67
-
69
+
70
+
68
71
  def _get_parser(prog, description):
69
72
  parser = argparse.ArgumentParser(prog=prog,
70
73
  description=description,
@@ -80,6 +83,7 @@ def _get_parser(prog, description):
80
83
  default=None, type=str)
81
84
  return parser
82
85
 
86
+
83
87
  def _tilupy_plot():
84
88
  parser = _get_parser('tilupy_plot', 'Plot thin-layer simulation results')
85
89
  parser.add_argument('--fmt', help=("Plot output format "
@@ -100,7 +104,8 @@ def _tilupy_plot():
100
104
  )
101
105
  args = parser.parse_args()
102
106
  plot_results(**vars(args))
103
-
107
+
108
+
104
109
  def _tilupy_to_raster():
105
110
  parser = _get_parser('tilupy_to_raster',
106
111
  'Convert simulation results to rasters')
@@ -111,11 +116,10 @@ def _tilupy_to_raster():
111
116
  args = parser.parse_args()
112
117
  # plot_results(parser.model, parser.res_name)
113
118
  to_raster(**vars(args))
114
-
115
-
119
+
120
+
116
121
  if __name__ == '__main__':
117
-
122
+
118
123
  # folder = 'd:/Documents/peruzzetto/tmp/test_shaltop/7p30e04_m3/coulomb'
119
124
  # plot_results('shaltop', 'h_max', '*18p00.txt', folder=folder)
120
125
  _tilupy_plot()
121
-
@@ -8,6 +8,10 @@ Created on Fri May 21 12:10:46 2021
8
8
  import os
9
9
  import numpy as np
10
10
 
11
+ import tilupy.make_topo
12
+ import tilupy.make_mass
13
+ import tilupy.plot
14
+
11
15
 
12
16
  def make_constant_slope(folder_out, theta=10, m_radius=50, m_height=50,
13
17
  m_x=None, m_y=None,
@@ -43,3 +47,35 @@ def make_constant_slope(folder_out, theta=10, m_radius=50, m_height=50,
43
47
  np.savetxt(os.path.join(folder_out, name+'.asc'), a,
44
48
  header=header_txt,
45
49
  comments='')
50
+
51
+
52
+ def gray99_topo_mass(dx=0.1, dy=0.1, save=False, folder_out=None):
53
+
54
+ # Initiate topography
55
+ X, Y, Z = tilupy.make_topo.gray99(dx=dx, dy=dy)
56
+
57
+ # Initiate initial mass. It is a spherical calotte above the topography,
58
+ # in Gray et al 99 (p. 1859) the resulting mass has a height of 0.22 m and a radius
59
+ # of 0.32 m (more precisely it is the length in the downslope direction)
60
+ # The correspondig radius of the sphere, and the offset from the topography
61
+ # in the topography normal direction (norm_offset) are deduced from these
62
+ # parameters
63
+
64
+ x0 = 0.06*np.cos(np.deg2rad(40))
65
+ hmass = 0.22
66
+ wmass = 0.32
67
+ radius = (wmass**2+hmass**2)/(2*hmass)
68
+ norm_offset = (hmass**2-wmass**2)/(2*hmass)
69
+ # Z = -np.tile(X, [len(Y), 1])*np.tan(np.deg2rad(20))
70
+ M = tilupy.make_mass.calotte(X, Y, Z, x0, 0,
71
+ radius, norm_offset=norm_offset,
72
+ res_type='true_normal')
73
+
74
+ return X, Y, Z, M
75
+
76
+
77
+ if __name__ == '__main__':
78
+
79
+ x, y, z, m = gray99_topo_mass(dx=0.01, dy=0.01)
80
+ tilupy.plot.plot_data_on_topo(x, y, z, m,
81
+ topo_kwargs=dict(level_min=0.1))
@@ -0,0 +1,108 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Fri Aug 4 19:27:09 2023
4
+
5
+ @author: peruzzetto
6
+ """
7
+
8
+ import numpy as np
9
+
10
+
11
+ def calotte(x, y, z, x0, y0, radius, norm_offset=0, res_type='projected_normal'):
12
+ """
13
+ Construct mass on topography as volume between sphere and topography.
14
+
15
+ Parameters
16
+ ----------
17
+ x : np.array
18
+ xaxis array, with length nx
19
+ y : np.array
20
+ yaxis array, with length ny
21
+ z : np.array
22
+ array of altitudes, of size (ny, nx). z[0, 0] has coordinates
23
+ (x[0], y[-1])
24
+ x0 : float
25
+ x position of the calotte
26
+ y0 : float
27
+ y position of the calotte
28
+ radius : float
29
+ radius of the shpere
30
+ norm_offset : float, optional
31
+ downwards offset between the sphere center and the topography, in the
32
+ direction normal to the topography. The default is 0.
33
+ res_type : string, optional
34
+ Type of thickness output. 'true_normal': real thickness in the
35
+ direction normal to the topography. 'vertical': Thickness in the
36
+ vertical direction. 'projected_normal': Thickness normal to the
37
+ topography is computed from the vertical thickness projected on
38
+ the axe normal to the topography. The default is 'projected_normal'.
39
+
40
+ Returns
41
+ -------
42
+ m : np.array
43
+ array of mass height, in the direction normal to topography
44
+
45
+ """
46
+ z = np.flip(z, axis=0).T
47
+
48
+ xmesh, ymesh = np.meshgrid(x, y, indexing='ij')
49
+ nx = len(x)
50
+ ny = len(y)
51
+
52
+ # Get altitude of mass center on topography
53
+ i0 = np.unravel_index(np.argmin(np.abs(x-x0), axis=None), (nx,))
54
+ j0 = np.unravel_index(np.argmin(np.abs(y-y0), axis=None), (ny,))
55
+ z0 = z[i0, j0]
56
+ # Topography gradient
57
+ [Fx, Fy] = np.gradient(z, x, y, edge_order=2)
58
+ Fz = np.ones((nx, ny))
59
+ c = 1/np.sqrt(1+Fx**2+Fy**2)
60
+ Fx = -Fx*c
61
+ Fy = -Fy*c
62
+ Fz = Fz*c
63
+ # Correct position from offset (shpere is moved downward,
64
+ # perpendicular to topography)
65
+ x0 = x0-norm_offset*Fx[i0, j0]
66
+ y0 = y0-norm_offset*Fy[i0, j0]
67
+ z0 = z0-norm_offset*Fz[i0, j0]
68
+
69
+ # Compute mass height only where relevant (ie around the mass center)
70
+ dist_to_mass = (xmesh-x0)**2+(ymesh-y0)**2
71
+ ind = (dist_to_mass <= radius**2)
72
+
73
+ B = 2*(Fx*(xmesh-x0)+Fy *
74
+ (ymesh-y0)+Fz*(z-z0))
75
+ C = (xmesh-x0)**2+(ymesh-y0)**2+(z-z0)**2-radius**2
76
+ D = B**2-4*C
77
+
78
+ # Intersection between shpere and normal to the topography, solution of
79
+ # t**2+B*t+C=0
80
+ m = np.zeros((nx, ny))
81
+
82
+ if res_type == 'true_normal':
83
+ # B = 2*(Fx[ind]*(xmesh[ind]-x0)+Fy[ind] *
84
+ # (ymesh[ind]-y0)+Fz[ind]*(z[ind]-z0))
85
+ # C = (xmesh[ind]-x0)**2+(ymesh[ind]-y0)**2+(z[ind]-z0)**2-radius**2
86
+ # D = B**2-4*C
87
+ B = 2*(Fx*(xmesh-x0)+Fy *
88
+ (ymesh-y0)+Fz*(z-z0))
89
+ C = (xmesh-x0)**2+(ymesh-y0)**2+(z-z0)**2-radius**2
90
+ D = B**2-4*C
91
+ ind = D > 0
92
+ t1 = (-B-np.sqrt(D))/2
93
+ t2 = (-B+np.sqrt(D))/2
94
+ ind2 = t1*t2 < 0
95
+ m[ind2] = np.maximum(t1[ind2], t2[ind2])
96
+
97
+ # Vertical thickness of calotte.
98
+ if res_type in ['vertical', 'projected_normal']:
99
+ zs = z0 + np.sqrt(radius**2 - (xmesh - x0)**2 - (ymesh - y0)**2)
100
+ zi = z0 - np.sqrt(radius**2 - (xmesh - x0)**2 - (ymesh - y0)**2)
101
+ ind = (z < zs) & (z > zi)
102
+ m[ind] = zs[ind] - z[ind]
103
+ if res_type == 'projected_normal':
104
+ m = m * c
105
+
106
+ m = np.flip(m.T, axis=0)
107
+
108
+ return m
@@ -0,0 +1,415 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Fri Aug 4 12:09:41 2023
4
+
5
+ @author: peruzzetto
6
+ """
7
+
8
+ import numpy as np
9
+ import scipy
10
+
11
+ import tilupy.plot
12
+
13
+
14
+ def gray99(nx=None, ny=None, xmin=-0.4, x1=1.75, x2=2.15,
15
+ xmax=3.2, ymax=0.5, R=1.1,
16
+ theta1=40, theta2=0, maxz=None, dx=0.01, dy=0.01, plot=False):
17
+ """
18
+ Construct channel as in Gray et all 99.
19
+
20
+ Input coordinates are in curvilinear coordinates along the reference
21
+ topography following the channel bottom. Output coordinates are in the
22
+ fixed cartesian frame.
23
+ Parameters
24
+ ----------
25
+ nx : int
26
+ Size of the grid in x direction
27
+ ny : int
28
+ Size of the y direction
29
+ dx : float, optional
30
+ Cell size of the x axis. if specified, nx is recomputed. Default: 0.01
31
+ dy : float, optional
32
+ Cell size of the y axis. if specified, ny is recomputed. Default: 0.01
33
+ xmin : float, optional
34
+ Minimum x coordinate. The default is -0.4.
35
+ x1 : float, optional
36
+ Min coordinate of the channel outlet (transition zone).
37
+ The default is 1.75.
38
+ x2 : float, optional
39
+ Max coordinate of the channel outlet (transition zone).
40
+ The default is 2.15.
41
+ xmax : float, optional
42
+ Maximum x coordinate. The default is 3.2.
43
+ ymax : float, optional
44
+ Maximum y coordinate the final yxais spans from -ymax to xmax.
45
+ The default is 0.5.
46
+ R : float, optional
47
+ Radius of curvature of the channel. The default is 1.1.
48
+ theta1 : float, optional
49
+ Slope of the channel in degree. The default is 40.
50
+ theta2 : float, optional
51
+ Slope after the channel. The default is 0.
52
+ maxz : float, optional
53
+ Maximum z coordinate. The default is None.
54
+ plot : boolean, optional
55
+ Plot result. The default is False.
56
+
57
+
58
+ Returns
59
+ -------
60
+ Xout : float nx*ny array
61
+ Mesh of X coordinates in the cartesian frame
62
+ Yout : float nx*ny array
63
+ Mesh of Y coordinates in the cartesian frame.
64
+ Zout : float nx*ny array
65
+ Mesh of Z coordinates in the cartesian frame.
66
+
67
+ """
68
+ theta1 = np.deg2rad(theta1)
69
+ theta2 = np.deg2rad(theta2)
70
+
71
+ if nx is None:
72
+ x = np.arange(xmin, xmax+dx/2, dx)
73
+ nx = len(x)
74
+ else:
75
+ x = np.linspace(xmin, xmax, nx)
76
+
77
+ if ny is None:
78
+ y = np.arange(-ymax, ymax+dy/2, dy)
79
+ ny = len(y)
80
+ else:
81
+ y = np.linspace(-ymax, ymax, ny)
82
+
83
+ ycurv = np.tile(y.reshape((1, ny)), (nx, 1))
84
+
85
+ # Superficial topography : channel
86
+ # alpha=1/(2*R)*np.sin(0.5*np.pi*(x-x2)/(x1-x2))**2
87
+ # alpha=1/(2*R)*np.abs(x-x2)**1/np.abs(x1-x2)**1
88
+ alpha = 1/(2*R)*(3*((x-x2)/(x1-x2))**2-2*((x-x2)/(x1-x2))**3)
89
+ alpha[x > x2] = 0
90
+ alpha[x < x1] = 1/(2*R)
91
+ alpha = np.tile(alpha.reshape((nx, 1)), (1, ny))
92
+
93
+ zchannel = alpha*np.abs(ycurv)**2
94
+ # plt.figure()
95
+ # plt.imshow(zchannel)
96
+
97
+ # del alpha
98
+
99
+ if not maxz:
100
+ maxz = R/2
101
+
102
+ zchannel[zchannel > maxz] = maxz
103
+
104
+ # Base topography in curvilinear system.
105
+ # The transition zone between x1 and x2 is a cylindre
106
+ zbase = -np.sin(theta2)*(x-xmax)
107
+
108
+ ind = (x <= x2) & (x >= x1)
109
+ angle = (x[ind]-x1)/(x2-x1)*(theta2-theta1)+theta1
110
+ R2 = (x2-x1)/(theta1-theta2)
111
+ z2 = -np.sin(theta2)*(x2-xmax)
112
+ zbase[ind] = R2*(1-np.cos(angle))-R2*(1-np.cos(theta2))+z2
113
+
114
+ ind = x <= x1
115
+ z1 = R2*(1-np.cos(theta1))-R2*(1-np.cos(theta2))+z2
116
+ zbase[ind] = -np.sin(theta1)*(x[ind]-x1)+z1
117
+ zbase = np.tile(zbase.reshape((nx, 1)), (1, ny))
118
+
119
+ # Conversion in fixed cartesian frame
120
+ zd = np.gradient(zbase, x[1]-x[0], edge_order=2, axis=0)
121
+ Xd = np.sqrt(1-zd**2)
122
+ X = scipy.integrate.cumtrapz(Xd, x, axis=0, initial=0)
123
+ X = X+xmin*np.cos(theta1)
124
+
125
+ # plt.figure()
126
+ # plt.plot(X[:,0])
127
+
128
+ del Xd
129
+
130
+ # Topography conversion in fixed cartesian frame
131
+ [Fx, Fy] = np.gradient(zbase, X[:, 0], ycurv[0, :], edge_order=2)
132
+ Fz = np.ones(zbase.shape)
133
+ costh = 1/np.sqrt(Fx**2+Fy**2+1) # Slope angle
134
+ Fx = -Fx*costh
135
+ Fy = -Fy*costh
136
+ Fz = Fz*costh
137
+ Z = zbase+zchannel*Fz
138
+ Xmesh = X+zchannel*Fx
139
+ Ymesh = ycurv+zchannel*Fy
140
+
141
+ # Reconstruction of regular cartesian mesh
142
+ Xout = np.linspace(Xmesh.min(), Xmesh.max(), nx)
143
+ Xout = np.tile(Xout.reshape((nx, 1)), (1, ny))
144
+ Yout = np.linspace(Ymesh.min(), Ymesh.max(), ny)
145
+ Yout = np.tile(Yout.reshape((1, ny)), (nx, 1))
146
+ Zout = scipy.interpolate.griddata((Xmesh.reshape(nx*ny),
147
+ Ymesh.reshape(nx*ny)),
148
+ Z.reshape(nx*ny),
149
+ (Xout, Yout), method='cubic')
150
+ Ztmp = scipy.interpolate.griddata((Xmesh.reshape(nx*ny),
151
+ Ymesh.reshape(nx*ny)),
152
+ Z.reshape(nx*ny),
153
+ (Xout, Yout), method='nearest')
154
+ ind = np.isnan(Zout)
155
+ Zout[ind] = Ztmp[ind]
156
+
157
+ del Ztmp
158
+ # fz=scipy.interpolate.Rbf(Xmesh,Ymesh,Z)
159
+ # Zout=fz(Xout,Yout)
160
+
161
+ if plot:
162
+ if theta2 == 0:
163
+ blod, thin = tilupy.plot.get_contour_intervals(np.nanmin(Zout),
164
+ np.nanmax(Zout))
165
+ level_min = thin
166
+ else:
167
+ level_min = None
168
+ tilupy.plot.plot_topo(Zout.T, Xout[:, 1], Yout[1, :],
169
+ level_min=level_min)
170
+
171
+ return Xout[:, 1], Yout[1, :], Zout.T
172
+
173
+
174
+ def channel(nx=None, ny=None, dx=None, dy=None,
175
+ xmin=-0.4, xmax=3.6, ymax=0.5, xstart_channel=0.65, xend_channel=2.3,
176
+ xstart_trans=0.4, xend_trans=2.75,
177
+ R=1.1, bend=0.2, nbends=1,
178
+ theta_start=40, theta_channel=40, theta_end=0,
179
+ plot=False, maxh=None, interp_method='linear'):
180
+ """
181
+ Generate channel with potential multiple bends. Input coordinates are
182
+ curvilinear along the flattened topography.
183
+
184
+ Parameters
185
+ ----------
186
+ nx : int
187
+ Size of the grid in x direction
188
+ ny : int
189
+ Size of the y direction
190
+ dx : float, optional
191
+ Cell size of the x axis. if specified, nx is recomputed. Default: 0.01
192
+ dy : float, optional
193
+ Cell size of the y axis. if specified, ny is recomputed. Default: 0.01
194
+ xmin : float, optional
195
+ Minimum x coordinate. The default is -0.4.
196
+ xmax : float, optional
197
+ Maximum x coordinate. The default is 3.2.
198
+ ymax : float, optional
199
+ Maximum y coordinate the final yxais spans from -ymax to xmax.
200
+ The default is 0.5.
201
+ xstart_channel : float, optional
202
+ Start of the channel. The default is 0.65.
203
+ xend_channel : float, optional
204
+ end of the channel. The default is 2.3.
205
+ xstart_trans : TYPE, optional
206
+ start of the transition zone before the channel start.
207
+ The default is 0.4.
208
+ xend_trans : TYPE, optional
209
+ End of the transition zone after the channel end. The default is 2.75.
210
+ R : float, optional
211
+ Radius of curvature of the channel. The default is 1.1.
212
+ bend : float, optional
213
+ Width of the channel bend. The default is 0.2.
214
+ nbends : ind, optional
215
+ Number of bends. The default is 1.
216
+ theta_start : float, optional
217
+ Slope before the channel. The default is 40.
218
+ theta_channel : float, optional
219
+ Slope of the channel. The default is 40.
220
+ theta_end : float, optional
221
+ Slope after the channel. The default is 0.
222
+ plot : bool, optional
223
+ Plot generated topography. The default is False.
224
+ maxh : float, optional
225
+ Depth of the channel. The default is None.
226
+ interp_method : string, optional
227
+ Interpolation method for converting the topography from curvilinear
228
+ coordinates to cartesian coordinates. The default is 'linear'.
229
+
230
+ Returns
231
+ -------
232
+ TYPE
233
+ DESCRIPTION.
234
+
235
+ """
236
+
237
+ theta_start = np.deg2rad(theta_start)
238
+ theta_channel = np.deg2rad(theta_channel)
239
+ theta_end = np.deg2rad(theta_end)
240
+
241
+ if ny is None and dy is None:
242
+ dy = ymax/100
243
+
244
+ if nx is None and dx is None:
245
+ if dy is not None:
246
+ dx = dy
247
+ else:
248
+ raise ValueError('nx or dx must be specified as input')
249
+
250
+ # x and y coordinates in the flattened topography
251
+ if nx is None:
252
+ xtopo = np.arange(xmin, xmax+dx/2, dx)
253
+ nx = len(xtopo)
254
+ else:
255
+ xtopo = np.linspace(xmin, xmax, nx)
256
+
257
+ if ny is None:
258
+ ytopo = np.arange(-ymax, ymax+dy/2, dy)
259
+ ny = len(ytopo)
260
+ else:
261
+ ytopo = np.linspace(-ymax, ymax, ny)
262
+
263
+ xtopo = np.tile(xtopo[:, np.newaxis], (1, ny))
264
+ ytopo = np.tile(ytopo[np.newaxis, :], (nx, 1))
265
+
266
+ # Height above flattened topography is a channel
267
+ # in alpha(x)*(y-thalweg(x))**2,
268
+
269
+ # alpha(x) is 1/2R in the channel, and depends on a transition
270
+ # function in the transition zones
271
+ def trans_function(x, x1, x2):
272
+ xx = 3*((x-x2)/(x1-x2))**2-2*((x-x2)/(x1-x2))**3
273
+ return xx
274
+ alpha = np.zeros((nx, ny))
275
+ ind = (xtopo > xstart_channel) & (xtopo < xend_channel)
276
+ alpha[ind] = 1/(2*R)
277
+ ind = (xtopo > xstart_trans) & (xtopo <= xstart_channel)
278
+ alpha[ind] = 1/(2*R)*trans_function(xtopo[ind],
279
+ xstart_channel, xstart_trans)
280
+ ind = (xtopo > xend_channel) & (xtopo <= xend_trans)
281
+ alpha[ind] = 1/(2*R)*trans_function(xtopo[ind], xend_channel, xend_trans)
282
+
283
+ # the thalweg is centered on y=0 outside [xstart_channel,xend_channel]. Inbetween,
284
+ # it is given by a cos**2
285
+ def end_bend(x, x1, x2):
286
+ yy = (bend/2)*(1+np.cos(np.pi*(x-x2)/(x1-x2)))
287
+ return yy
288
+
289
+ def mid_bend(x, x1, x2):
290
+ yy = bend*np.cos(np.pi*(x-x1)/(x2-x1))
291
+ return yy
292
+ thalweg = np.zeros((nx, ny))
293
+
294
+ if nbends > 0:
295
+ step = (xend_channel-xstart_channel)/nbends
296
+
297
+ ind = (xtopo > xstart_channel) & (xtopo < xstart_channel+step/2)
298
+ thalweg[ind] = end_bend(
299
+ xtopo[ind], xstart_channel, xstart_channel+step/2)
300
+ ind = (xtopo >= xend_channel-step/2) & (xtopo < xend_channel)
301
+ thalweg[ind] = (-1)**(nbends+1)*end_bend(xtopo[ind],
302
+ xend_channel, xend_channel-step/2)
303
+ if nbends > 1:
304
+ ind = (xtopo >= xstart_channel+step /
305
+ 2) & (xtopo < xend_channel-step/2)
306
+ thalweg[ind] = mid_bend(
307
+ xtopo[ind], xstart_channel+step/2, xstart_channel+(3/2)*step)
308
+
309
+ htopo = alpha*(ytopo-thalweg)**2
310
+
311
+ if not maxh:
312
+ maxh = R/2
313
+
314
+ htopo[htopo > maxh] = maxh
315
+
316
+ # Reconstruction of bz the basal topography. The real topo is given by
317
+ # bz+\vec{n}*htopo. Slopes of bz are given by theta_* outside the transition
318
+ # zones. We use a cylinder shape inbetween. This is done by computing the slope
319
+ # angle of bz, and using then -sin(slope_angle)=d(bz)/d(xtopo)
320
+
321
+ slope_angle = np.zeros((nx, ny))
322
+ ind = xtopo < xstart_trans
323
+ slope_angle[ind] = theta_start
324
+ ind = xtopo >= xend_trans
325
+ slope_angle[ind] = theta_end
326
+ ind = (xtopo >= xstart_channel) & (xtopo < xend_channel)
327
+ slope_angle[ind] = theta_channel
328
+
329
+ ind = (xtopo >= xstart_trans) & (xtopo < xstart_channel)
330
+ slope_angle[ind] = (xtopo[ind]-xstart_trans)/(xstart_channel -
331
+ xstart_trans)
332
+ slope_angle[ind] = slope_angle[ind]*(theta_channel-theta_start)+theta_start
333
+
334
+ ind = (xtopo >= xend_channel) & (xtopo < xend_trans)
335
+ slope_angle[ind] = (xtopo[ind]-xend_trans)/(xend_channel -
336
+ xend_trans)
337
+ slope_angle[ind] = slope_angle[ind]*(theta_channel-theta_end)+theta_end
338
+
339
+ bz = scipy.integrate.cumtrapz(-np.sin(slope_angle),
340
+ xtopo, axis=0, initial=0)
341
+ bz = bz-np.min(bz)
342
+
343
+ # Get the coordinates of (xtopo,ytopo) in the cartesian reference frame
344
+ # by=ytopo
345
+ bx = scipy.integrate.cumtrapz(
346
+ np.cos(slope_angle), xtopo, axis=0, initial=0)
347
+ bx = bx+xmin*np.cos(theta_start)
348
+
349
+ # Vector normal to topography in cartesian coordinates
350
+ # (nx,ny,nz)=(-sin(theta),0,cos(theta))
351
+ # as the topography does vary in the y direction
352
+ # The real topography is thus given in cartesian coordinates by
353
+ # (xcart,ycart,zcart)=(bx,by,bz)+htopo(nx,ny,nz)
354
+ xcart = bx+htopo*np.sin(slope_angle)
355
+ zcart = bz+htopo*np.cos(slope_angle)
356
+
357
+ # Reconstruct regular mesh for interpolation
358
+ Xout = np.linspace(xcart[0, 0], xcart[-1, 0], nx)
359
+ Yout = ytopo
360
+ Xout = np.tile(Xout[:, np.newaxis], (1, ny))
361
+ Zout = scipy.interpolate.griddata((xcart.reshape(nx*ny),
362
+ ytopo.reshape(nx*ny)),
363
+ zcart.reshape(nx*ny),
364
+ (Xout, Yout), method=interp_method)
365
+ Ztmp = scipy.interpolate.griddata((xcart.reshape(nx*ny),
366
+ ytopo.reshape(nx*ny)),
367
+ zcart.reshape(nx*ny),
368
+ (Xout, Yout), method='nearest')
369
+ ind = np.isnan(Zout)
370
+ Zout[ind] = Ztmp[ind]
371
+
372
+ if plot:
373
+ if theta_end == 0:
374
+ blod, thin = tilupy.plot.get_contour_intervals(np.nanmin(Zout),
375
+ np.nanmax(Zout))
376
+ level_min = thin
377
+ else:
378
+ level_min = None
379
+ tilupy.plot.plot_topo(Zout.T, Xout[:, 1], Yout[1, :],
380
+ level_min=level_min)
381
+
382
+ return Xout[:, 1], Yout[1, :], Zout.T, thalweg
383
+
384
+
385
+ if __name__ == '__main__':
386
+
387
+ # %% Test gray99
388
+ X, Y, Z = gray99(plot=True)
389
+
390
+ # %% Test synthetic channel
391
+ bend = 0.25
392
+ R = 0.2
393
+
394
+ nx = 600
395
+ ny = 300
396
+
397
+ xmin = 0.1
398
+ xmax = 4.5
399
+ xstart_trans = -0.3
400
+ xstart_channel = 0.2
401
+ xend_channel = 2.3
402
+ xend_trans = 2.75
403
+ ymax = 1
404
+
405
+ theta_start = 10
406
+ theta_channel = 10
407
+ theta_end = 0
408
+ x, y, z, t = channel(nx, ny, xmin=xmin, xmax=xmax, ymax=ymax,
409
+ xstart_channel=xstart_channel,
410
+ xend_channel=xend_channel,
411
+ xstart_trans=xstart_trans,
412
+ theta_start=theta_start,
413
+ theta_end=theta_end,
414
+ theta_channel=theta_channel,
415
+ R=R, bend=bend, maxh=R, plot=True)
@@ -50,26 +50,27 @@ def write_params_file(params, directory=None,
50
50
  with open(os.path.join(directory, file_name), 'w') as file_params:
51
51
  for name in params:
52
52
  val = params[name]
53
- if type(val) == int or type(val) == np.int64:
53
+ if isinstance(val, int) or isinstance(val, np.int64):
54
54
  file_params.write('{:s} {:d}\n'.format(name, val))
55
- if type(val) == float or type(val) == np.float64:
55
+ if isinstance(val, float) or isinstance(val, np.float64):
56
56
  file_params.write('{:s} {:.8G}\n'.format(name, val))
57
- if type(val) == str:
57
+ if isinstance(val, str):
58
58
  file_params.write('{:s} {:s}\n'.format(name, val))
59
59
 
60
+
60
61
  def raster_to_shaltop_txtfile(file_in, file_out, folder_out=None):
61
-
62
+
62
63
  if folder_out is not None:
63
64
  file_out = os.path.join(folder_out, file_out)
64
-
65
+
65
66
  x, y, rast = tilupy.raster.read_raster(file_in)
66
67
  np.savetxt(file_out,
67
68
  np.reshape(np.flip(rast, axis=0), (rast.size, 1)),
68
69
  fmt='%.12G')
69
-
70
+
70
71
  res = dict(x0=x[0], y0=y[0], dx=x[1]-x[0], dy=y[1]-y[0],
71
72
  nx=len(x), ny=len(y))
72
-
73
+
73
74
  return res
74
75
 
75
76
 
@@ -17,6 +17,10 @@ import seaborn as sns
17
17
 
18
18
  from mpl_toolkits.axes_grid1 import make_axes_locatable
19
19
 
20
+ BOLD_CONTOURS_INTV = [0.1, 0.2, 0.5, 1, 2., 5, 10, 20, 50, 100, 200, 500, 1000]
21
+ NB_THIN_CONTOURS = 10
22
+ NB_BOLD_CONTOURS = 3
23
+
20
24
 
21
25
  def centered_map(cmap, vmin, vmax, ncolors=256):
22
26
  """
@@ -55,11 +59,37 @@ def centered_map(cmap, vmin, vmax, ncolors=256):
55
59
  return new_map
56
60
 
57
61
 
58
- def plot_topo(z, x, y, contour_step=None, nlevels=25, level_min=None,
59
- step_contour_bold=0, contour_labels_properties=None,
62
+ def get_contour_intervals(zmin, zmax, nb_bold_contours=None,
63
+ nb_thin_contours=None):
64
+
65
+ if nb_thin_contours is None:
66
+ nb_thin_contours = NB_THIN_CONTOURS
67
+ if nb_bold_contours is None:
68
+ nb_bold_contours = NB_BOLD_CONTOURS
69
+
70
+ intv = (zmax - zmin) / nb_bold_contours
71
+ i = np.argmin(np.abs(np.array(BOLD_CONTOURS_INTV) - intv))
72
+
73
+ bold_intv = BOLD_CONTOURS_INTV[i]
74
+ if BOLD_CONTOURS_INTV[i] != BOLD_CONTOURS_INTV[0]:
75
+ if bold_intv - intv > 0:
76
+ bold_intv = BOLD_CONTOURS_INTV[i-1]
77
+
78
+ if nb_thin_contours is None:
79
+ thin_intv = bold_intv / NB_THIN_CONTOURS
80
+ if (zmax - zmin)/bold_intv > 5:
81
+ thin_intv = thin_intv*2
82
+ else:
83
+ thin_intv = bold_intv / nb_thin_contours
84
+
85
+ return bold_intv, thin_intv
86
+
87
+
88
+ def plot_topo(z, x, y, contour_step=None, nlevels=None, level_min=None,
89
+ step_contour_bold='auto', contour_labels_properties=None,
60
90
  label_contour=True, contour_label_effect=None,
61
91
  axe=None,
62
- vert_exag=1, fraction=1, ndv=0, uniform_grey=None,
92
+ vert_exag=1, fraction=1, ndv=-9999, uniform_grey=None,
63
93
  contours_prop=None, contours_bold_prop=None,
64
94
  figsize=None,
65
95
  interpolation=None,
@@ -111,7 +141,7 @@ def plot_topo(z, x, y, contour_step=None, nlevels=25, level_min=None,
111
141
  fraction : TYPE, optional
112
142
  DESCRIPTION. The default is 1.
113
143
  ndv : TYPE, optional
114
- DESCRIPTION. The default is 0.
144
+ DESCRIPTION. The default is -9999.
115
145
 
116
146
  Returns
117
147
  -------
@@ -126,6 +156,12 @@ def plot_topo(z, x, y, contour_step=None, nlevels=25, level_min=None,
126
156
  y[-1]+dy/2]
127
157
  ls = mcolors.LightSource(azdeg=azdeg, altdeg=altdeg)
128
158
 
159
+ auto_bold_intv = None
160
+
161
+ if nlevels is None and contour_step is None:
162
+ auto_bold_intv, contour_step = get_contour_intervals(np.nanmin(z),
163
+ np.nanmax(z))
164
+
129
165
  if level_min is None:
130
166
  if contour_step is not None:
131
167
  level_min = np.ceil(np.nanmin(z)/contour_step)*contour_step
@@ -166,8 +202,16 @@ def plot_topo(z, x, y, contour_step=None, nlevels=25, level_min=None,
166
202
  contours_bold_prop = dict(alpha=0.8, colors='k',
167
203
  linewidths=0.8)
168
204
 
205
+ if step_contour_bold == 'auto':
206
+ if auto_bold_intv is None:
207
+ auto_bold_intv, _ = get_contour_intervals(np.nanmin(z),
208
+ np.nanmax(z))
209
+ step_contour_bold = auto_bold_intv
210
+
169
211
  if step_contour_bold > 0:
170
212
  lmin = np.ceil(np.nanmin(z)/step_contour_bold)*step_contour_bold
213
+ if lmin < level_min:
214
+ lmin = lmin + step_contour_bold
171
215
  levels = np.arange(lmin, np.nanmax(z), step_contour_bold)
172
216
  cs = axe.contour(x, y, np.flip(z, axis=0),
173
217
  extent=im_extent,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: tilupy
3
- Version: 0.1.3
3
+ Version: 0.1.5
4
4
  Summary: Thin-layer models unified processing tool
5
5
  Author-email: Marc Peruzzetto <m.peruzzetto@brgm.fr>
6
6
  License: CeCILL-C FREE SOFTWARE LICENSE AGREEMENT
@@ -524,12 +524,19 @@ Keywords: thin-layer,shallow-water,display,simulation,model,processing,benchmark
524
524
  Classifier: License :: CeCILL-C Free Software License Agreement (CECILL-C)
525
525
  Classifier: Programming Language :: Python
526
526
  Classifier: Programming Language :: Python :: 3
527
- Requires-Python: >=3.10
527
+ Requires-Python: >=3.8
528
528
  Description-Content-Type: text/markdown
529
+ License-File: LICENSE
530
+ Requires-Dist: seaborn
531
+ Requires-Dist: requests
532
+ Requires-Dist: scipy
529
533
  Provides-Extra: test
534
+ Requires-Dist: pytest; extra == "test"
530
535
  Provides-Extra: dev
536
+ Requires-Dist: pipreqs; extra == "dev"
531
537
  Provides-Extra: gis
532
- License-File: LICENSE
538
+ Requires-Dist: rasterio; extra == "gis"
539
+ Requires-Dist: shapely; extra == "gis"
533
540
 
534
541
  # tilupy
535
542
 
@@ -553,7 +560,7 @@ It contains one submodule per thin-layer model for writing and reading raw input
553
560
  Outputs are then easily compared between different simulations / models. The models themselves are not part of this package and must
554
561
  be installed separately.
555
562
 
556
- Note that `tilupy` is still under development, thus only minimal documentation is available at the moment and testing is underway.
563
+ Note that `tilupy` is still under development, thus only minimal documentation is available at the moment, and testing is underway.
557
564
  Contributions are feedback are most welcome. Reading and writing is available for the `SHALTOP` model (most commonly used by the author) and `r.avaflow`
558
565
  (only partly maintained).
559
566
 
@@ -10,6 +10,8 @@ src/tilupy/cmd.py
10
10
  src/tilupy/compare.py
11
11
  src/tilupy/download_data.py
12
12
  src/tilupy/initdata.py
13
+ src/tilupy/make_mass.py
14
+ src/tilupy/make_topo.py
13
15
  src/tilupy/notations.py
14
16
  src/tilupy/plot.py
15
17
  src/tilupy/raster.py
@@ -28,4 +30,5 @@ src/tilupy/models/ravaflow/read.py
28
30
  src/tilupy/models/shaltop/__init__.py
29
31
  src/tilupy/models/shaltop/initsimus.py
30
32
  src/tilupy/models/shaltop/read.py
33
+ tests/test_generated_data.py
31
34
  tests/test_shaltop.py
@@ -1,5 +1,6 @@
1
1
  seaborn
2
2
  requests
3
+ scipy
3
4
 
4
5
  [dev]
5
6
  pipreqs
@@ -0,0 +1,17 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Fri Aug 4 12:45:15 2023
4
+
5
+ @author: peruzzetto
6
+ """
7
+
8
+ import numpy as np
9
+
10
+ import tilupy.make_topo
11
+
12
+
13
+ def test_topo_gray():
14
+
15
+ x, y, z = tilupy.make_topo.gray99()
16
+
17
+ assert (np.abs(y[-1] - 0.5) < 1e-6) & (len(x) == 361)
@@ -0,0 +1,106 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Wed Jul 19 15:39:38 2023
4
+
5
+ @author: peruzzetto
6
+ """
7
+
8
+ import os
9
+ import shutil
10
+
11
+ import tilupy.models.shaltop.initsimus as shinit
12
+ import tilupy.cmd
13
+
14
+
15
+ def test_shaltop_raster_to_input(folder_data):
16
+
17
+ folder_simus = os.path.join(folder_data, 'frankslide', 'shaltop')
18
+
19
+ raster_topo = os.path.join(folder_data, 'frankslide', 'rasters',
20
+ 'Frankslide_topography.asc')
21
+
22
+ file_topo_sh = os.path.join(folder_simus, 'topography.d')
23
+
24
+ if os.path.isfile(file_topo_sh):
25
+ os.remove(file_topo_sh)
26
+
27
+ shinit.raster_to_shaltop_txtfile(raster_topo, file_topo_sh)
28
+
29
+ raster_pile = os.path.join(folder_data, 'frankslide', 'rasters',
30
+ 'Frankslide_pile.asc')
31
+ file_mass_sh = os.path.join(folder_simus, 'init_mass.d')
32
+
33
+ if os.path.isfile(file_mass_sh):
34
+ os.remove(file_mass_sh)
35
+
36
+ shinit.raster_to_shaltop_txtfile(raster_pile, file_mass_sh)
37
+
38
+ assert os.path.isfile(file_topo_sh) & os.path.isfile(file_mass_sh)
39
+
40
+
41
+ def test_shaltop_make_read_param_file(folder_data):
42
+
43
+ params = dict(nx=201, ny=201,
44
+ per=201*20,
45
+ pery=201*20,
46
+ # Simulation maximum time in seconds (not comutation time)
47
+ tmax=20,
48
+ dt_im=10, # Time interval (s) between snapshots recordings
49
+ file_z_init='topography.d', # Name of topography input file
50
+ file_m_init='init_mass.d', # name of init mass input file
51
+ initz=0, # Topography is read from file
52
+ ipr=0, # Initial mass is read from file
53
+ hinit_vert=1, # Initial is given as vertical thicknesses and
54
+ # must be converted to thicknesses normal to topography
55
+ eps0=1e-13, # Minimum value for thicknesses and velocities
56
+ # choice of rheology (Coulomb with constant basal friction)
57
+ icomp=1,
58
+ # Min x value (used for plots after simulation is over)
59
+ x0=1000,
60
+ y0=2000) # Min y value (used for plots after simulation is over)
61
+
62
+ deltas = [15, 20, 25]
63
+ folder_simus = os.path.join(folder_data, 'frankslide', 'shaltop')
64
+ files_created = True
65
+
66
+ for delta in deltas:
67
+ params_txt = 'delta_{:05.2f}'.format(delta).replace('.', 'p')
68
+ param_file_path = os.path.join(folder_simus, params_txt + '.txt')
69
+ if os.path.isfile(param_file_path):
70
+ os.remove(param_file_path)
71
+ # Specify folder where outputs are stored
72
+ params['folder_output'] = params_txt
73
+ params['delta1'] = delta # Specify the friction coefficient
74
+ # Write parameter file
75
+ shinit.write_params_file(params, directory=folder_simus,
76
+ file_name=params_txt + '.txt')
77
+
78
+ files_created = files_created & os.path.isfile(param_file_path)
79
+ if not files_created:
80
+ break
81
+
82
+ assert files_created
83
+
84
+
85
+ def test_shaltop_plot_results(folder_data):
86
+
87
+ folder_simus = os.path.join(folder_data, 'frankslide', 'shaltop')
88
+ params_files = 'delta_*p00.txt'
89
+ folder_ress = [os.path.join(folder_data, 'frankslide', 'shaltop',
90
+ 'delta_{:d}p00'.format(delta), 'plots')
91
+ for delta in [15, 20, 25]]
92
+ for folder in folder_ress:
93
+ if os.path.isdir(folder):
94
+ shutil.rmtree(folder)
95
+ tilupy.cmd.plot_results('shaltop', 'h', params_files, folder_simus,
96
+ save=True, display_plot=False,
97
+ figsize=(10/2.54, 10/2.54))
98
+ files_plots = ['h_0000.png', 'h_0001.png', 'h_0002.png']
99
+
100
+ all_files_created = True
101
+ for folder in folder_ress:
102
+ for file in files_plots:
103
+ file_path = os.path.join(folder, file)
104
+ all_files_created = all_files_created & os.path.isfile(file_path)
105
+
106
+ assert all_files_created
@@ -1,66 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """
3
- Created on Wed Jul 19 15:39:38 2023
4
-
5
- @author: peruzzetto
6
- """
7
-
8
- import os
9
-
10
- import tilupy.models.shaltop.initsimus as shinit
11
-
12
-
13
- def test_shaltop_raster_to_input(folder_data):
14
-
15
- raster_topo = os.path.join(folder_data, 'frankslide', 'rasters',
16
- 'Frankslide_topography.asc')
17
-
18
- folder_simus = os.path.join(folder_data, 'frankslide', 'shaltop')
19
-
20
- file_topo_sh = os.path.join(folder_simus, 'topography.d')
21
-
22
- if os.path.isfile(file_topo_sh):
23
- os.remove(file_topo_sh)
24
-
25
- shinit.raster_to_shaltop_txtfile(raster_topo, file_topo_sh)
26
-
27
- assert os.path.isfile(file_topo_sh)
28
-
29
- def test_shaltop_make_read_param_file(folder_data):
30
-
31
- params = dict(nx=201, ny=201,
32
- per=201*20,
33
- pery=201*20,
34
- tmax=100, # Simulation maximum time in seconds (not comutation time)
35
- dt_im=10, # Time interval (s) between snapshots recordings
36
- file_z_init = 'topography.d', # Name of topography input file
37
- file_m_init = 'init_mass.d',# name of init mass input file
38
- initz=0, # Topography is read from file
39
- ipr=0, # Initial mass is read from file
40
- hinit_vert=1, # Initial is given as vertical thicknesses and
41
- # must be converted to thicknesses normal to topography
42
- eps0=1e-13, #Minimum value for thicknesses and velocities
43
- icomp=1, # choice of rheology (Coulomb with constant basal friction)
44
- x0=1000, # Min x value (used for plots after simulation is over)
45
- y0=2000) # Min y value (used for plots after simulation is over)
46
-
47
- deltas = [15, 20, 25]
48
- folder_simus = os.path.join(folder_data, 'frankslide', 'shaltop')
49
- files_created = True
50
-
51
- for delta in deltas:
52
- params_txt = 'delta_{:05.2f}'.format(delta).replace('.', 'p')
53
- param_file_path = os.path.join(folder_simus,params_txt + '.txt')
54
- if os.path.isfile(param_file_path):
55
- os.remove(param_file_path)
56
- params['folder_output'] = params_txt # Specify folder where outputs are stored
57
- params['delta1'] = delta # Specify the friction coefficient
58
- #Write parameter file
59
- shinit.write_params_file(params, directory=folder_simus,
60
- file_name=params_txt + '.txt')
61
-
62
- files_created = files_created & os.path.isfile(param_file_path)
63
- if not files_created:
64
- break
65
-
66
- assert files_created
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes