tilupy 2.0.0__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.
tilupy/initdata.py ADDED
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+
4
+ import os
5
+ import numpy as np
6
+
7
+ import tilupy.make_topo
8
+ import tilupy.make_mass
9
+ import tilupy.raster
10
+
11
+
12
+ def create_topo_constant_slope(folder_out: str,
13
+ xmax: int = 30,
14
+ ymax: int = 25,
15
+ cell_size: float = 0.5,
16
+ theta: int = 5,
17
+ mass_type: str = 'r',
18
+ r_center: tuple = (7.5, 12.5),
19
+ r_radius: tuple = (3.75, 3.75),
20
+ s_vertex: list = [0, 5, 0, 25],
21
+ h_max: float = 3.75,
22
+ description: str = "No informations."
23
+ ) -> list[str, np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
24
+ """
25
+ Generates a synthetic topography and initial mass, saves them as ASCII files,
26
+ and stores all configuration parameters in a dedicated folder.
27
+
28
+ Parameters
29
+ ----------
30
+ folder_out : str
31
+ Output folder.
32
+ xmax : int
33
+ Domain length in the X direction (in meters).
34
+ ymax : int
35
+ Domain length in the Y direction (in meters).
36
+ cell_size : float
37
+ Spatial resolution of the grid (in meters).
38
+ theta : int
39
+ Slope angle of the topography (in degrees).
40
+ mass_type : str
41
+ Shape of the initial mass: 'r' for ellipse, 's' for rectangle.
42
+ r_center : tuple
43
+ Center (x, y) of the elliptical initial mass.
44
+ r_radius : tuple
45
+ Radii (rx, ry) of the elliptical initial mass.
46
+ s_vertex : list
47
+ Rectangle boundaries [xmin, xmax, ymin, ymax] for the rectangular mass.
48
+ h_max : float
49
+ Maximum height of the initial mass.
50
+ description : str
51
+ Text description of the configuration.
52
+
53
+ Returns
54
+ -------
55
+ list[str, numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]
56
+ folder_path : str
57
+ Absolute path to the output directory.
58
+ x, y : numpy.ndarray, numpy.ndarray
59
+ Meshgrid coordinates.
60
+ z : numpy.ndarray
61
+ Topography data.
62
+ m : numpy.ndarray
63
+ Initial mass distribution.
64
+ """
65
+ # Create mesh
66
+ x = np.linspace(0, xmax, int(np.round(xmax / cell_size)) + 1)
67
+ y = np.linspace(0, ymax, int(np.round(ymax / cell_size)) + 1)
68
+ xmesh, ymesh = np.meshgrid(x, y)
69
+
70
+ # Topography slope
71
+ slope = np.tan(np.deg2rad(theta))
72
+
73
+ # Topography array
74
+ z = -slope * (xmesh - xmax)
75
+
76
+ # Initial mass
77
+ if mass_type != 'r' and mass_type != 's':
78
+ mass_type = 'r'
79
+
80
+ p = dict(
81
+ hmax=h_max,
82
+ mass_type=mass_type,
83
+ r_center = r_center if mass_type=='r' else None,
84
+ r_radius = r_radius if mass_type=='r' else None,
85
+ s_vertex = s_vertex if mass_type=='s' else None,
86
+ )
87
+
88
+ if p["mass_type"] == 'r':
89
+ m = (
90
+ 1
91
+ - (xmesh - p["r_center"][0]) ** 2 / p["r_radius"][0] ** 2
92
+ - (ymesh - p["r_center"][1]) ** 2 / p["r_radius"][1] ** 2
93
+ )
94
+ m = np.maximum(m * p["hmax"], 0)
95
+
96
+ elif p["mass_type"] == 's':
97
+ xmin_r, xmax_r, ymin_r, ymax_r = p["s_vertex"]
98
+ in_x = np.logical_and(xmesh >= xmin_r, xmesh <= xmax_r)
99
+ in_y = np.logical_and(ymesh >= ymin_r, ymesh <= ymax_r)
100
+ mask = np.logical_and(in_x, in_y)
101
+ m = np.zeros_like(z)
102
+ m[mask] = p["hmax"]
103
+
104
+ nbr_cell = np.count_nonzero(m > 0)
105
+
106
+ p["nbr_cell"] = nbr_cell
107
+
108
+ folder_name = f"x{xmax}_y{ymax}_" + "dx{:04.2f}_".format(cell_size).replace(".", "p") + "theta{:02.0f}_".format(theta) + mass_type + f"{nbr_cell}"
109
+ folder_path = os.path.join(folder_out, folder_name)
110
+
111
+ # Create folder
112
+ if not os.path.isdir(folder_path):
113
+ os.mkdir(folder_path)
114
+ print(f"Create folder: {folder_name}")
115
+ else:
116
+ print(f"Existing topography: {folder_name}")
117
+
118
+ # Create parameters file
119
+ with open(os.path.join(folder_path, "parameters.txt"), "w") as file:
120
+ file.write(f"xmax {xmax}\nymax {ymax}\ncell_size {cell_size}\ntheta {theta}\n\n")
121
+
122
+ for param, value in p.items():
123
+ file.write(f"{param} {value}\n")
124
+
125
+ file.write("\n")
126
+ file.write(description)
127
+
128
+ # Save topography
129
+ file_topo_out = os.path.join(folder_path, "topography.asc")
130
+ file_mass_out = os.path.join(folder_path, "init_mass.asc")
131
+
132
+ tilupy.raster.write_ascii(x, y, z, file_topo_out)
133
+ tilupy.raster.write_ascii(x, y, m, file_mass_out)
134
+
135
+ return folder_path, x, y, z, m
136
+
137
+
138
+ def gray99_topo_mass(dx: float = 0.1,
139
+ dy: float = 0.1,
140
+ res_type: str = "true_normal"
141
+ ) -> list[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
142
+ """Create Gray99 topographic and mass test.
143
+
144
+ Create an initial spherical calotte above the topography, resulting as a mass with a
145
+ height of 0.22 m and a radius of 0.32 m (more precisely it is the length in the downslope
146
+ direction), following the indications in Gray et al 99 (p. 1859).
147
+ The correspondig radius of the sphere, and the offset from the topography in the topography
148
+ normal direction (norm_offset) are deduced from these parameters.
149
+
150
+ See also Gig 3 in Wieland, Gray and Hutter (1999)
151
+
152
+ Parameters
153
+ ----------
154
+ dx : float, optional
155
+ Cell size of the x axis, by default 0.1
156
+ dy : float, optional
157
+ Cell size of the y axis, by default 0.1
158
+ res_type : str, optional
159
+ Type of thickness output:
160
+
161
+ - 'true_normal': Real thickness in the direction normal to the topography.
162
+ - 'vertical': Thickness in the vertical direction.
163
+ - 'projected_normal': Thickness normal to the topography is computed from the vertical
164
+ thickness projected on the axe normal to the topography.
165
+
166
+ The default is 'true_normal'.
167
+
168
+ Returns
169
+ -------
170
+ list[numpy.ndarray, numpy.ndarray, numpy.ndarray, numpy.ndarray]
171
+ X : numpy.ndarray
172
+ Mesh of X coordinates in the cartesian frame (nx*ny).
173
+ Y : numpy.ndarray
174
+ Mesh of Y coordinates in the cartesian frame (nx*ny).
175
+ Z : numpy.ndarray
176
+ Mesh of Z coordinates in the cartesian frame (nx*ny).
177
+ M : numpy.ndarray
178
+ Array of mass height, in the direction normal to topography.
179
+ """
180
+ # Initiate topography
181
+ X, Y, Z = tilupy.make_topo.gray99(dx=dx, dy=dy)
182
+
183
+ x0 = 0.06 * np.cos(np.deg2rad(40))
184
+ hmass = 0.22
185
+ wmass = 0.32
186
+ radius = (wmass**2 + hmass**2) / (2 * hmass)
187
+ norm_offset = (wmass**2 - hmass**2) / (2 * hmass)
188
+ # Z = -np.tile(X, [len(Y), 1])*np.tan(np.deg2rad(20))
189
+
190
+ M = tilupy.make_mass.calotte(X,
191
+ Y,
192
+ Z,
193
+ x0,
194
+ 0,
195
+ radius,
196
+ norm_offset=norm_offset,
197
+ res_type=res_type)
198
+
199
+ return X, Y, Z, M
200
+
201
+
202
+ """
203
+ if __name__ == "__main__":
204
+ x, y, z, m = gray99_topo_mass(dx=0.01, dy=0.01)
205
+ axe = pytopomap.plot.plot_data_on_topo(x, y, z, m, topo_kwargs=dict(level_min=0.1))
206
+ plt.show()
207
+ """
tilupy/initsimus.py ADDED
@@ -0,0 +1,50 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import importlib
4
+
5
+
6
+ def write(model_name: str,
7
+ raster_topo: str,
8
+ raster_mass: str,
9
+ tmax : float,
10
+ dt_im : float,
11
+ rheology_type: str,
12
+ rheology_params: dict = None,
13
+ folder_out: str = None,
14
+ **kwargs
15
+ ):
16
+ """
17
+ Dynamically imports the corresponding initiation module from
18
+ :data:`tilupy.models.<code>.initsimus` and use the corresponding :data:`write_simu()` function.
19
+
20
+ Parameters
21
+ ----------
22
+ model_name : str
23
+ Model to create simulation files.
24
+ raster_topo : str, optional
25
+ Path for an ASCII topography.
26
+ raster_mass : str, optional
27
+ Path for an ASCII initial mass.
28
+ tmax : float
29
+ Maximum simulation time.
30
+ dt_im : float
31
+ Output image interval (in time steps).
32
+ rheology_type : str
33
+ Rheology to use for the simulation.
34
+ rheology_params : dict
35
+ Parameters specific to the selected rheology.
36
+ folder_out : str, optional
37
+ Output folder where simulation inputs will be saved.
38
+ **kwargs
39
+ Additional arguments for specific models.
40
+ """
41
+ module = importlib.import_module("tilupy.models." + model_name + ".initsimus")
42
+
43
+ module.write_simu(raster_topo=raster_topo,
44
+ raster_mass=raster_mass,
45
+ tmax=tmax,
46
+ dt_im=dt_im,
47
+ rheology_type=rheology_type,
48
+ rheology_params=rheology_params,
49
+ folder_out=folder_out,
50
+ **kwargs)
tilupy/make_mass.py ADDED
@@ -0,0 +1,111 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import numpy as np
4
+
5
+
6
+ def calotte(x: np.ndarray,
7
+ y: np.ndarray,
8
+ z: np.ndarray,
9
+ x0: float,
10
+ y0: float,
11
+ radius: float,
12
+ norm_offset: float = 0,
13
+ res_type: str = 'projected_normal'
14
+ ) -> np.ndarray:
15
+ """Construct mass on topography as volume between sphere and topography.
16
+
17
+ Parameters
18
+ ----------
19
+ x : numpy.ndarray
20
+ X-axis array, with length nx.
21
+ y : numpy.ndarray
22
+ Y-axis array, with length ny.
23
+ z : numpy.ndarray
24
+ Array of altitudes, of size (ny, nx). z[0, 0] has coordinates
25
+ (x[0], y[-1]).
26
+ x0 : float
27
+ X position of the calotte.
28
+ y0 : float
29
+ Y position of the calotte.
30
+ radius : float
31
+ Radius of the shpere.
32
+ norm_offset : float, optional
33
+ Downwards offset between the sphere center and the topography, in the
34
+ direction normal to the topography, by default 0.
35
+ res_type : string, optional
36
+ Type of thickness output:
37
+
38
+ - 'true_normal': Real thickness in the direction normal to the topography.
39
+ - 'vertical': Thickness in the vertical direction.
40
+ - 'projected_normal': Thickness normal to the topography is computed from the vertical
41
+ thickness projected on the axe normal to the topography.
42
+
43
+ The default is 'projected_normal'.
44
+
45
+ Returns
46
+ -------
47
+ numpy.ndarray
48
+ Array of mass height, in the direction normal to topography.
49
+ """
50
+ z = np.flip(z, axis=0).T
51
+
52
+ xmesh, ymesh = np.meshgrid(x, y, indexing='ij')
53
+ nx = len(x)
54
+ ny = len(y)
55
+
56
+ # Get altitude of mass center on topography
57
+ i0 = np.unravel_index(np.argmin(np.abs(x-x0), axis=None), (nx,))
58
+ j0 = np.unravel_index(np.argmin(np.abs(y-y0), axis=None), (ny,))
59
+ z0 = z[i0, j0]
60
+ # Topography gradient
61
+ [Fx, Fy] = np.gradient(z, x, y, edge_order=2)
62
+ Fz = np.ones((nx, ny))
63
+ c = 1/np.sqrt(1+Fx**2+Fy**2)
64
+ Fx = -Fx*c
65
+ Fy = -Fy*c
66
+ Fz = Fz*c
67
+ # Correct position from offset (shpere is moved downward,
68
+ # perpendicular to topography)
69
+ x0 = x0-norm_offset*Fx[i0, j0]
70
+ y0 = y0-norm_offset*Fy[i0, j0]
71
+ z0 = z0-norm_offset*Fz[i0, j0]
72
+
73
+ # Compute mass height only where relevant (ie around the mass center)
74
+ dist_to_mass = (xmesh-x0)**2+(ymesh-y0)**2
75
+ ind = (dist_to_mass <= radius**2)
76
+
77
+ B = 2*(Fx*(xmesh-x0)+Fy * (ymesh-y0)+Fz*(z-z0))
78
+ C = (xmesh-x0)**2+(ymesh-y0)**2+(z-z0)**2-radius**2
79
+ D = B**2-4*C
80
+
81
+ # Intersection between shpere and normal to the topography, solution of
82
+ # t**2+B*t+C=0
83
+ m = np.zeros((nx, ny))
84
+
85
+ if res_type == 'true_normal':
86
+ # B = 2*(Fx[ind]*(xmesh[ind]-x0)+Fy[ind] *
87
+ # (ymesh[ind]-y0)+Fz[ind]*(z[ind]-z0))
88
+ # C = (xmesh[ind]-x0)**2+(ymesh[ind]-y0)**2+(z[ind]-z0)**2-radius**2
89
+ # D = B**2-4*C
90
+ B = 2*(Fx*(xmesh-x0)+Fy *
91
+ (ymesh-y0)+Fz*(z-z0))
92
+ C = (xmesh-x0)**2+(ymesh-y0)**2+(z-z0)**2-radius**2
93
+ D = B**2-4*C
94
+ ind = D > 0
95
+ t1 = (-B-np.sqrt(D))/2
96
+ t2 = (-B+np.sqrt(D))/2
97
+ ind2 = t1*t2 < 0
98
+ m[ind2] = np.maximum(t1[ind2], t2[ind2])
99
+
100
+ # Vertical thickness of calotte.
101
+ if res_type in ['vertical', 'projected_normal']:
102
+ zs = z0 + np.sqrt(radius**2 - (xmesh - x0)**2 - (ymesh - y0)**2)
103
+ zi = z0 - np.sqrt(radius**2 - (xmesh - x0)**2 - (ymesh - y0)**2)
104
+ ind = (z < zs) & (z > zi)
105
+ m[ind] = zs[ind] - z[ind]
106
+ if res_type == 'projected_normal':
107
+ m = m * c
108
+
109
+ m = np.flip(m.T, axis=0)
110
+
111
+ return m