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.
@@ -0,0 +1,273 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ Created on Tue Jun 1 15:27:36 2021
5
+
6
+ @author: peruzzetto
7
+ """
8
+ import os
9
+
10
+ import numpy as np
11
+ import tilupy.read
12
+
13
+ # Dictionnary with results names lookup table, to match code output names
14
+ LOOKUP_NAMES = dict(h='hflow',
15
+ u='vflow', ux='vflowx', uy='vflowy',
16
+ hu='momentum', hu2='ek',
17
+ vol='vol', ekint='ekint')
18
+
19
+ # Classify results
20
+ STATES_OUTPUT = ['h', 'ux', 'uy']
21
+ forces = ['facc', 'fcurv', 'ffric', 'fgrav', 'fpression']
22
+ FORCES_OUTPUT = []
23
+ for axis in ['x', 'y']:
24
+ for f in forces:
25
+ FORCES_OUTPUT.append(f + axis)
26
+
27
+
28
+ def read_params(file):
29
+ """
30
+ Read simulation parameters from file.
31
+
32
+ Parameters
33
+ ----------
34
+ file : str
35
+ Parameters file.
36
+
37
+ Returns
38
+ -------
39
+ params : dict
40
+ Dictionnary with parameters
41
+
42
+ """
43
+ params = dict()
44
+ if not file.endswith('.txt'):
45
+ prefix = file.sep('/')[-1].sep('_')[0]
46
+ file = os.path.join(file, prefix+'_files',
47
+ prefix+'_documentation.txt')
48
+
49
+ with open(file, 'r') as f:
50
+ for line in f:
51
+ (key, val) = line.split('\t')
52
+ try:
53
+ params[key] = float(val)
54
+ except ValueError:
55
+ if val == 'TRUE':
56
+ params[key] = True
57
+ if val == 'FALSE':
58
+ params[key] = False
59
+ else:
60
+ params[key] = val
61
+
62
+ return params
63
+
64
+
65
+ def read_ascii(file):
66
+ """
67
+ Read ascii grid file to numpy ndarray.
68
+
69
+ Parameters
70
+ ----------
71
+ file : TYPE
72
+ DESCRIPTION.
73
+
74
+ Returns
75
+ -------
76
+ None.
77
+
78
+ """
79
+ dem = np.loadtxt(file, skiprows=6)
80
+ # dem = np.flip(dem, axis=0).T
81
+ grid = {}
82
+ with open(file, 'r') as fid:
83
+ for i in range(6):
84
+ tmp = fid.readline().split()
85
+ grid[tmp[0]] = float(tmp[1])
86
+ try:
87
+ x0 = grid['xllcenter']
88
+ y0 = grid['yllcenter']
89
+ except KeyError:
90
+ x0 = grid['xllcorner']
91
+ y0 = grid['yllcorner']
92
+ nx = int(grid['ncols'])
93
+ ny = int(grid['nrows'])
94
+ dx = dy = grid['cellsize']
95
+ x = np.linspace(x0, x0+(nx-1)*dx, nx)
96
+ y = np.linspace(y0, y0+(ny-1)*dy, ny)
97
+
98
+ return x, y, dem
99
+
100
+
101
+ def read_asciis(file_prefix, folder=None, ind=None, nodigit=False):
102
+ """
103
+ Read mutiple ascii grid file matching prefix.
104
+
105
+ Parameters
106
+ ----------
107
+ file : TYPE
108
+ DESCRIPTION.
109
+ ind : TYPE, optional
110
+ DESCRIPTION. The default is None.
111
+
112
+ Returns
113
+ -------
114
+ None.
115
+
116
+ """
117
+ if folder is None:
118
+ folder = os.getcwd()
119
+
120
+ files_tmp = os.listdir(folder)
121
+ files = []
122
+ for ff in files_tmp:
123
+ # test is file begins with file_prefix
124
+ if ff.startswith(file_prefix) and ff.endswith('.asc'):
125
+ letter = ff.split(file_prefix)[1][0]
126
+ # After file_prefix, character must be either '.' or a digit
127
+ if nodigit:
128
+ if letter == '.':
129
+ files.append(ff)
130
+ else:
131
+ if letter.isdigit() or letter == '.':
132
+ files.append(ff)
133
+
134
+ files.sort()
135
+
136
+ if ind is not None:
137
+ if ind == 'final':
138
+ files = [files[-1]]
139
+ elif ind == 'initial':
140
+ files = [files[0]]
141
+ else:
142
+ files = [ff for ff in files if int(ff[-8:-4]) in ind]
143
+
144
+ files = [os.path.join(folder, ff) for ff in files]
145
+
146
+ dem = np.loadtxt(files[0], skiprows=6)
147
+ if len(files) > 1:
148
+ dem = dem[:, :, np.newaxis]
149
+ for ff in files[1:]:
150
+ _, _, dem2 = np.loadtxt(ff, skiprows=6)
151
+ dem = np.concatenate((dem, dem2[:, :, np.newaxis]), axis=2)
152
+
153
+ dem = np.squeeze(dem)
154
+
155
+ return dem
156
+
157
+
158
+ class Results(tilupy.read.Results):
159
+ """Results of shaltop simulations."""
160
+
161
+ def __init__(self, text_rheol=None, folder_base=None, **varargs):
162
+ """
163
+ Init simulation results.
164
+
165
+ Parameters
166
+ ----------
167
+ file_params : str
168
+ File where simulation parameters will be read
169
+
170
+ """
171
+ self.code = 'ravaflow'
172
+ self.prefix = text_rheol
173
+ self.folder_base = folder_base
174
+ file_params = os.path.join(folder_base,
175
+ self.prefix + '_results',
176
+ self.prefix + '_files',
177
+ self.prefix + '_documentation.txt')
178
+ self.params = read_params(file_params)
179
+
180
+ self.folder_ascii = os.path.join(folder_base,
181
+ self.prefix + '_results',
182
+ self.prefix + '_ascii')
183
+ self.folder_files = os.path.join(folder_base,
184
+ self.prefix + '_results',
185
+ self.prefix + '_files')
186
+
187
+ self.set_axes()
188
+
189
+ # Get time of outputs
190
+ with open(os.path.join(self.folder_files,
191
+ self.prefix+'_summary.txt')) as fid:
192
+ self.tim = []
193
+ for line in fid:
194
+ res = line.split()
195
+ if len(res) > 0:
196
+ if res[0].isdigit():
197
+ self.tim.append(float(res[4]))
198
+
199
+ def set_axes(self, x=None, y=None, **varargs):
200
+ """Set x and y axes."""
201
+ dd = self.params['Cell size']
202
+ x = np.arange(self.params['Western boundary']+dd/2,
203
+ self.params['Eastern boundary'],
204
+ dd)
205
+ y = np.arange(self.params['Southern boundary']+dd/2,
206
+ self.params['Northern boundary'],
207
+ dd)
208
+ self.x = x
209
+ self.y = y
210
+ self.nx = len(x)
211
+ self.ny = len(y)
212
+
213
+ def set_zinit(self, zinit=None):
214
+ """Set zinit, initial topography."""
215
+ path_zinit = os.path.join(self.folder_ascii,
216
+ self.prefix+'_elev.asc')
217
+ self.zinit = np.loadtxt(path_zinit, skiprows=6)
218
+
219
+ def get_temporal_output(self, name, d=None, t=None, **varargs):
220
+ """
221
+ Read 2D time dependent simulation results.
222
+
223
+ Parameters
224
+ ----------
225
+ name : str
226
+ Name of output.
227
+ d : ndarray, optional
228
+ Data to be read. If None, will be computed.
229
+ The default is None.
230
+ t : ndarray, optional
231
+ Time of results snapshots (1D array), matching last dimension of d.
232
+ If None, will be computed. The default is None.
233
+ **varargs : TYPE
234
+ DESCRIPTION.
235
+
236
+ """
237
+ # Read thicknesses or velocity components
238
+ file_prefix = self.prefix + '_' + LOOKUP_NAMES[name]
239
+ d = read_asciis(file_prefix, folder=self.folder_ascii)
240
+
241
+ return tilupy.read.TemporalResults(name, d, self.tim)
242
+
243
+ def get_static_output(self, name, stat,
244
+ d=None, from_file=False, **varargs):
245
+ """
246
+ Read 2D time dependent simulation results.
247
+
248
+ Parameters
249
+ ----------
250
+ name : str
251
+ Name of output.
252
+ d : ndarray, optional
253
+ Data to be read. Last dimension is for time.
254
+ If None, will be computed.
255
+ The default is None.
256
+ **varargs : TYPE
257
+ DESCRIPTION.
258
+
259
+ """
260
+ if stat in ['initial', 'final']:
261
+ file_prefix = self.prefix + '_' + LOOKUP_NAMES[name]
262
+ d = read_asciis(file_prefix, folder=self.folder_ascii, ind=stat)
263
+ elif stat == 'max' and from_file:
264
+ file = '{:s}_{:s}_{:s}.asc'.format(self.prefix,
265
+ LOOKUP_NAMES[name],
266
+ stat)
267
+ file = os.path.join(self.folder_ascii, file)
268
+ d = np.loadtxt(file, skiprows=6)
269
+ else:
270
+ data = self.get_temporal_output(name)
271
+ d = data.get_temporal_stat(stat).d
272
+
273
+ return tilupy.read.StaticResults(name+stat, d)
File without changes
@@ -0,0 +1,298 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import os
4
+
5
+ import numpy as np
6
+ import tilupy.read
7
+
8
+ # Classify results
9
+ AVAILABLE_OUTPUT = ["h", "hvert", "u", "hu", "hu2", "ux", "uy", "hux", "huy"]
10
+ """All output available for a shaltop simulation.
11
+
12
+ Implemented states:
13
+
14
+ - h : Flow thickness (normal to the surface)
15
+ - hux : Momentum flux component in X direction
16
+ - huy : Momentum flux component in Y direction
17
+
18
+ Output computed from other output:
19
+
20
+ - hvert : True vertical flow thickness
21
+ - ux : Velocity component in X direction
22
+ - uy : Velocity component in Y direction
23
+ - u : Norm of the velocity (from ux and uy)
24
+ - hu : Momentum flux (from h and u)
25
+ - hu2 : Convective momentum flux (from h and u)
26
+ """
27
+
28
+
29
+ def extract_saval_ascii(path: str) -> np.ndarray:
30
+ """Extract ascii file data generated by saval2D.
31
+
32
+ Parameters
33
+ ----------
34
+ path : str
35
+ Path to the ascii file.
36
+
37
+ Returns
38
+ -------
39
+ numpy.ndarray
40
+ Values in the ascii file.
41
+ """
42
+ with open(path, 'r') as f:
43
+ lines = f.readlines()
44
+ start_index = 6
45
+
46
+ h_str = lines[start_index:]
47
+
48
+ h = [list(map(float, line.split())) for line in h_str if line.strip()]
49
+ return np.array(h)
50
+
51
+
52
+ class Results(tilupy.read.Results):
53
+ """Results of saval2D simulations.
54
+
55
+ This class is the results class for saval2D. Reading results from saval2D outputs
56
+ are done in this class.
57
+
58
+ This class has all the global and quick attributes of the parent class. The quick
59
+ attributes are only computed if needed and can be deleted to clean memory.
60
+
61
+ In addition to these attributes, there are those necessary for the operation of
62
+ reading the saval2D results.
63
+
64
+ Parameters
65
+ ----------
66
+ folder : str
67
+ Path to the folder containing the simulation files.
68
+ raster_topo : str
69
+ Topographic raster name.
70
+
71
+ Attributes
72
+ ----------
73
+ _simu_inputs : str
74
+ Path to the input folder of saval2D simulation.
75
+ _simu_outputs : str
76
+ Path to the output folder of saval2D simulation.
77
+ _raster : str
78
+ Raster file name.
79
+ _params : dict
80
+ Dictionary storing all simulation parameters.
81
+ """
82
+ def __init__(self, folder, raster_topo="mntsimulation.asc"):
83
+ super().__init__()
84
+ self._code = "saval2D"
85
+
86
+ self._folder = folder
87
+ self._folder_output = folder
88
+
89
+ self._simu_inputs = os.path.join(folder, "inputs") if os.path.exists(os.path.join(folder, "inputs")) else None
90
+ self._simu_outputs = os.path.join(folder, "outputs") if os.path.exists(os.path.join(folder, "outputs")) else None
91
+
92
+ if not raster_topo.endswith(".asc"):
93
+ raster_topo = raster_topo + ".asc"
94
+ self._raster = raster_topo
95
+
96
+ self._params = dict()
97
+
98
+ if self._simu_inputs is not None:
99
+ self._x, self._y, self._zinit = tilupy.raster.read_ascii(os.path.join(self._simu_inputs,
100
+ self._raster))
101
+ self._nx, self._ny = len(self._x), len(self._y)
102
+ self._dx = self._x[1] - self._x[0]
103
+ self._dy = self._y[1] - self._y[0]
104
+
105
+ self._params["nx"] = len(self.x)
106
+ self._params["ny"] = len(self.y)
107
+
108
+ # Rheology
109
+ rheol = self.get_rheological_parameters(os.path.join(self._simu_outputs, "log.txt"))
110
+ self._params["tau/rho"] = rheol[0]
111
+ self._params["mu"] = rheol[1]
112
+ self._params["xi"] = rheol[2]
113
+
114
+ # Create self._tim
115
+ self._extract_output("X")
116
+
117
+
118
+ def get_rheological_parameters(self, path_to_log: str) -> list[str]:
119
+ """Get rheological parameters of a saval2D simulation.
120
+
121
+ Parameters
122
+ ----------
123
+ path_to_log : str
124
+ Path to the log file containing the value of the rheological parameters.
125
+
126
+ Returns
127
+ -------
128
+ list[str]
129
+ List of rheological parameters : tau/rho, mu and xi.
130
+ """
131
+ values = None
132
+ with open(path_to_log, "r") as f:
133
+ for line in f:
134
+ line = line.strip()
135
+ try:
136
+ parts = list(map(float, line.split()))
137
+ if len(parts) == 3:
138
+ values = parts
139
+ break
140
+ except ValueError:
141
+ continue
142
+ return values
143
+
144
+
145
+ def get_times(self, path: str) -> list[float]:
146
+ """Get simulation time steps.
147
+
148
+ Parameters
149
+ ----------
150
+ path : str
151
+ Path to the log file.
152
+
153
+ Returns
154
+ -------
155
+ list[float]
156
+ List of recorded time steps.
157
+ """
158
+ t_list = []
159
+ with open(path, 'r') as f:
160
+ lines = f.readlines()
161
+
162
+ start_index = 16
163
+ for line in lines[start_index:]:
164
+ if line.strip() == '':
165
+ continue
166
+ else:
167
+ _, t, _, _, _ = line.split()
168
+ t_list.append(float(t))
169
+
170
+ return t_list
171
+
172
+
173
+ def _extract_output(self,
174
+ name: str,
175
+ **kwargs
176
+ ) -> tilupy.read.TemporalResults2D | tilupy.read.AbstractResults:
177
+ """Result extraction for saval2D files.
178
+
179
+ Parameters
180
+ ----------
181
+ name : str
182
+ Wanted output. Can access to variables in :data:`AVAILABLE_OUTPUT`.
183
+
184
+ Returns
185
+ -------
186
+ tilupy.read.TemporalResults2D | tilupy.read.AbstractResults
187
+ Wanted output. If no output computed, return an object of :class:`tilupy.read.AbstractResults`.
188
+ """
189
+ # Read thicknesses or velocity components
190
+ d = None
191
+ t = None
192
+ notation = None
193
+
194
+ tim = [0]
195
+ t_list = self.get_times(os.path.join(self._simu_outputs, "log.txt"))
196
+
197
+ _, _, h_init = tilupy.raster.read_ascii(os.path.join(self._simu_inputs, "zdepsimulation.asc"))
198
+
199
+ h_list = [h_init]
200
+
201
+ ux_list = []
202
+ uy_list = []
203
+ u_list = []
204
+ ux_list.append(np.zeros_like(h_init))
205
+ uy_list.append(np.zeros_like(h_init))
206
+ u_list.append(np.zeros_like(h_init))
207
+
208
+ qx_list = []
209
+ qy_list = []
210
+ q_list = []
211
+ qx_list.append(np.zeros_like(h_init))
212
+ qy_list.append(np.zeros_like(h_init))
213
+ q_list.append(np.zeros_like(h_init))
214
+
215
+ for T in range(len(t_list)):
216
+ h_t = extract_saval_ascii(os.path.join(self._simu_outputs, f"resuh{T+1}.asc"))
217
+ qu_t = extract_saval_ascii(os.path.join(self._simu_outputs, f"resuqu{T+1}.asc"))
218
+ qv_t = extract_saval_ascii(os.path.join(self._simu_outputs, f"resuqv{T+1}.asc"))
219
+
220
+ # Condition to avoid flow velocity on part with no fluid
221
+ h_t[h_t<0.0001] = 0
222
+
223
+ ux_t = np.divide(qu_t, h_t, out=np.zeros_like(qu_t), where=h_t != 0)
224
+ uy_t = np.divide(qv_t, h_t, out=np.zeros_like(qv_t), where=h_t != 0)
225
+
226
+ u_t = np.sqrt(ux_t**2 + uy_t**2)
227
+ q_t = np.sqrt(qu_t**2 + qv_t**2)
228
+
229
+ h_list.append(h_t)
230
+
231
+ ux_list.append(ux_t)
232
+ uy_list.append(uy_t)
233
+ u_list.append(u_t)
234
+
235
+ qx_list.append(qu_t)
236
+ qy_list.append(qv_t)
237
+ q_list.append(q_t)
238
+
239
+ tim.append(t_list[T])
240
+
241
+ if self._tim is None:
242
+ self._tim = np.array(tim)
243
+
244
+ extracted_outputs = {"h": np.stack(h_list, axis=-1),
245
+ "u": np.stack(u_list, axis=-1),
246
+ "hu": np.stack(q_list, axis=-1),
247
+ "ux": np.stack(ux_list, axis=-1),
248
+ "uy": np.stack(uy_list, axis=-1),
249
+ "hux": np.stack(qx_list, axis=-1),
250
+ "huy": np.stack(qy_list, axis=-1),
251
+ }
252
+
253
+ if name in ["h", "u", "hu", "ux", "uy", "hux", "huy"]:
254
+ d = extracted_outputs[name]
255
+ t = self._tim
256
+
257
+ if name == "hu2":
258
+ d = extracted_outputs["hu"] * extracted_outputs["u"]
259
+ t = self._tim
260
+
261
+ elif name == "hvert":
262
+ if self._costh is None:
263
+ self._costh = self.compute_costh()
264
+ d = extracted_outputs["h"] / self._costh[:, :, np.newaxis]
265
+ t = self._tim
266
+
267
+ # if name == "ek":
268
+ # if self._costh is None:
269
+ # self._costh = self.compute_costh()
270
+
271
+ # d = []
272
+ # for i in range(len(self._tim)):
273
+ # d.append(np.sum((np.stack(available_outputs["hu"], axis=-1)[:, :, i] *
274
+ # np.stack(available_outputs["u"], axis=-1)[:, :, i] *
275
+ # self._dx *
276
+ # self._dy)
277
+ # / self._costh[:, :]))
278
+ # d = np.array(d)
279
+ # t = self._tim
280
+
281
+ if t is None:
282
+ return tilupy.read.AbstractResults(name, d, notation=notation)
283
+
284
+ else:
285
+ if d.ndim == 3:
286
+ return tilupy.read.TemporalResults2D(name,
287
+ d,
288
+ t,
289
+ notation=notation,
290
+ x=self._x,
291
+ y=self._y,
292
+ z=self._zinit)
293
+ return None
294
+
295
+
296
+ def _read_from_file(self, *args, **kwargs):
297
+ """Not useful"""
298
+ return "No _read_from_file for Saval2D."
File without changes