tilupy 0.1.4__py3-none-any.whl → 0.1.5__py3-none-any.whl

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.

tilupy/calibration.py CHANGED
@@ -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
tilupy/initdata.py CHANGED
@@ -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))
tilupy/make_mass.py ADDED
@@ -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
tilupy/make_topo.py ADDED
@@ -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
 
tilupy/plot.py CHANGED
@@ -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.4
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
@@ -529,6 +529,7 @@ Description-Content-Type: text/markdown
529
529
  License-File: LICENSE
530
530
  Requires-Dist: seaborn
531
531
  Requires-Dist: requests
532
+ Requires-Dist: scipy
532
533
  Provides-Extra: dev
533
534
  Requires-Dist: pipreqs ; extra == 'dev'
534
535
  Provides-Extra: gis
@@ -559,7 +560,7 @@ It contains one submodule per thin-layer model for writing and reading raw input
559
560
  Outputs are then easily compared between different simulations / models. The models themselves are not part of this package and must
560
561
  be installed separately.
561
562
 
562
- 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.
563
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`
564
565
  (only partly maintained).
565
566
 
@@ -1,11 +1,13 @@
1
1
  tilupy/__init__.py,sha256=4r-aUNht-u_rUoYIyz3BOFEew11xCURWpSRYEfc8Dis,515
2
- tilupy/calibration.py,sha256=O3UT-H9-eebaDttAN7GCQ4QDXynCb4IvwXSs8dHsL0E,3424
2
+ tilupy/calibration.py,sha256=AGZq1YMI60d0RYzto1xdXglZ8DfSRCfo5gCAHzvwfwg,3318
3
3
  tilupy/cmd.py,sha256=A_Xv9rq0e6vx4QIBQx_EunjDBKITXrZpQjQpjWu6tKA,4260
4
4
  tilupy/compare.py,sha256=5PkDmMen_-yJImowvFJYB3IV0x0xs9WSFAYhX81wFLg,6294
5
5
  tilupy/download_data.py,sha256=D_R9l5XtgsmxEoKOXXPlWFV6q3e9SMa7asRRy-blQvw,1057
6
- tilupy/initdata.py,sha256=UmUMff9zIu8df0s5prV6DVBD-KzBqdTUfMDJiDDzmQI,1334
6
+ tilupy/initdata.py,sha256=3vk-pw5IzCOKimBrGiT1iBxtqp2aJ9uqAY3GN7LFPYw,2579
7
+ tilupy/make_mass.py,sha256=XM4HzwVLho_QDZzoXxVQCVJwNeMWawg-nRaDxiN9vW0,3442
8
+ tilupy/make_topo.py,sha256=6fby5Zkl657pNgPFNWFF37-sORQvyBKsYn9atKESB_I,14302
7
9
  tilupy/notations.py,sha256=s4p9jsz0n2nXNxxVG5SU14j37b2kqYoIcTKvSehNOOI,3509
8
- tilupy/plot.py,sha256=bD1MeZyTH3hOYwbqto2mn1v49aUI2dJvagGy2qKwUwY,16552
10
+ tilupy/plot.py,sha256=awffgtd_X2ChltgnucIngVSeTNrwZ2YALLEhxYqxHdw,18044
9
11
  tilupy/raster.py,sha256=4d_-RWGHHO0ZXkjwaHPEOBxPjb36HW8ISq_7z32sgQg,3605
10
12
  tilupy/read.py,sha256=vyhbqBeh3ade8sXcCZK8ZZIjjVX7Dr9E7h1JhwY8mZw,12602
11
13
  tilupy/utils.py,sha256=P4OyIGggrUVC0aKqTlZuwGhUN-nyORI870S9QFWWJAA,4118
@@ -14,11 +16,11 @@ tilupy/models/ravaflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
14
16
  tilupy/models/ravaflow/initsimus.py,sha256=VCr_k2HuYecbX7KYS54FtY109OCzlslJ9pY1J1_iWNQ,5104
15
17
  tilupy/models/ravaflow/read.py,sha256=xKuMFRHyC0SV6QubMOcQ9EpJ3c843g2RKViDq7g-yHY,7900
16
18
  tilupy/models/shaltop/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
- tilupy/models/shaltop/initsimus.py,sha256=X0FSwwDSHWh-ODEu_zTZMCpB4cR4yFQpiDAF5ufNXxM,4600
19
+ tilupy/models/shaltop/initsimus.py,sha256=bezToIzFE25pk6qHRyGcnMQ5Du-s_MVP_KjVZI8KVwI,4601
18
20
  tilupy/models/shaltop/read.py,sha256=LetbNT19KvOJx0gdMOnlHxr0KlAg8TN3FmfBB9NIct0,9209
19
- tilupy-0.1.4.dist-info/LICENSE,sha256=bNrodROEaIAk5t7X7Db_7d2CjDfHBp_FjweStZO2gZk,21863
20
- tilupy-0.1.4.dist-info/METADATA,sha256=uP3gHp-Qq6dV7ydTSALDWiLh5r9AEJZ4XsTCblVw1QM,41853
21
- tilupy-0.1.4.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
22
- tilupy-0.1.4.dist-info/entry_points.txt,sha256=jf71F8J1P5s-zVt5BIxKZDmCIaoUqryMCtT7tc3BkkA,104
23
- tilupy-0.1.4.dist-info/top_level.txt,sha256=jhJY_A8Vzmqub_dVy0wPSfelUqFPjHMZOaepGVcrpxA,7
24
- tilupy-0.1.4.dist-info/RECORD,,
21
+ tilupy-0.1.5.dist-info/LICENSE,sha256=bNrodROEaIAk5t7X7Db_7d2CjDfHBp_FjweStZO2gZk,21863
22
+ tilupy-0.1.5.dist-info/METADATA,sha256=LGpV1Uqymnq-BNbSGsZt9VHxkBP4heel40BObjEtzxA,41875
23
+ tilupy-0.1.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
24
+ tilupy-0.1.5.dist-info/entry_points.txt,sha256=jf71F8J1P5s-zVt5BIxKZDmCIaoUqryMCtT7tc3BkkA,104
25
+ tilupy-0.1.5.dist-info/top_level.txt,sha256=jhJY_A8Vzmqub_dVy0wPSfelUqFPjHMZOaepGVcrpxA,7
26
+ tilupy-0.1.5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.40.0)
2
+ Generator: bdist_wheel (0.42.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5