tilupy 0.1.4__py3-none-any.whl → 1.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.

Potentially problematic release.


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

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)
@@ -7,24 +7,23 @@ Created on Tue May 25 15:18:31 2021
7
7
  """
8
8
 
9
9
  import os
10
+ import posixpath
10
11
  import numpy as np
11
12
 
13
+ from tilupy.utils import format_path_linux
14
+
12
15
  import tilupy.notations
13
16
  import tilupy.raster
14
17
 
15
- README_PARAM_MATCH = dict(tmax='tmax',
16
- CFL='cflhyp',
17
- h_min='eps0',
18
- dt_im_output='dt_im')
19
18
 
20
- SHALTOP_LAW_ID = dict(coulomb=1,
21
- voellmy=8,
22
- bingham=6,
23
- muI=7)
19
+ README_PARAM_MATCH = dict(
20
+ tmax="tmax", CFL="cflhyp", h_min="eps0", dt_im_output="dt_im"
21
+ )
22
+
23
+ SHALTOP_LAW_ID = dict(coulomb=1, voellmy=8, bingham=6, muI=7)
24
24
 
25
25
 
26
- def write_params_file(params, directory=None,
27
- file_name='params.txt'):
26
+ def write_params_file(params, directory=None, file_name="params.txt"):
28
27
  """
29
28
  Write params file for shaltop simulations
30
29
 
@@ -47,32 +46,145 @@ def write_params_file(params, directory=None,
47
46
 
48
47
  if directory is None:
49
48
  directory = os.getcwd()
50
- with open(os.path.join(directory, file_name), 'w') as file_params:
49
+ with open(os.path.join(directory, file_name), "w") as file_params:
51
50
  for name in params:
52
51
  val = params[name]
53
- if type(val) == int or type(val) == np.int64:
54
- file_params.write('{:s} {:d}\n'.format(name, val))
55
- if type(val) == float or type(val) == np.float64:
56
- file_params.write('{:s} {:.8G}\n'.format(name, val))
57
- if type(val) == str:
58
- file_params.write('{:s} {:s}\n'.format(name, val))
52
+ if isinstance(val, int) or isinstance(val, np.int64):
53
+ file_params.write("{:s} {:d}\n".format(name, val))
54
+ if isinstance(val, float) or isinstance(val, np.float64):
55
+ file_params.write("{:s} {:.8G}\n".format(name, val))
56
+ if isinstance(val, str):
57
+ file_params.write("{:s} {:s}\n".format(name, val))
58
+
59
59
 
60
60
  def raster_to_shaltop_txtfile(file_in, file_out, folder_out=None):
61
-
62
61
  if folder_out is not None:
63
62
  file_out = os.path.join(folder_out, file_out)
64
-
63
+
65
64
  x, y, rast = tilupy.raster.read_raster(file_in)
66
- np.savetxt(file_out,
67
- np.reshape(np.flip(rast, axis=0), (rast.size, 1)),
68
- fmt='%.12G')
69
-
70
- res = dict(x0=x[0], y0=y[0], dx=x[1]-x[0], dy=y[1]-y[0],
71
- nx=len(x), ny=len(y))
72
-
65
+ np.savetxt(
66
+ file_out,
67
+ np.reshape(np.flip(rast, axis=0), (rast.size, 1)),
68
+ fmt="%.12G",
69
+ )
70
+
71
+ res = dict(
72
+ x0=x[0], y0=y[0], dx=x[1] - x[0], dy=y[1] - y[0], nx=len(x), ny=len(y)
73
+ )
74
+
73
75
  return res
74
76
 
75
77
 
78
+ def write_job_files(
79
+ dirs,
80
+ param_files,
81
+ file_job,
82
+ job_name,
83
+ max_time_hours=24,
84
+ ncores_per_node=6,
85
+ partitions="cpuall,data,datanew",
86
+ shaltop_file="shaltop",
87
+ folder_conf_in_job=None,
88
+ replace_path=None,
89
+ number_conf_file=True,
90
+ ):
91
+ """
92
+ Write job/conf files for slurm jobs. The conf contains all the commands
93
+ needed to run each simulation (one command per simulation).
94
+
95
+ Parameters
96
+ ----------
97
+ dirs : list of string
98
+ list of paths where simus will be run.
99
+ param_files : list string
100
+ list of shaltop parameter files.
101
+ file_job : string
102
+ name of job file called by sbatch.
103
+ job_name : string
104
+ name of conf file used by file_job.
105
+ max_time_hours : int, optional
106
+ Maximum job duration in hours before stop. The default is 24.
107
+ ncores_per_node : int, optional
108
+ Number of cores per nodes. Used to know the number of nodes required
109
+ for the job. The default is 6.
110
+ partitions : string, optional
111
+ Names of partitions on which jobs can be launched.
112
+ The default is "cpuall,data,datanew".
113
+ shaltop_file : string, optional
114
+ Bash command used to call shaltop. Can be a path.
115
+ The default is "shaltop".
116
+ folder_conf_in_job : string, optional
117
+ Folder where the conf file is located. The default is the folder
118
+ path of file_job.
119
+ replace_path : list, optional
120
+ replace replace_path[0] by replace_path[1] for every path in dir. This
121
+ is used if simulations are prepared and run on two different machines
122
+ (e.g. laptop and cluster).
123
+ The default is None.
124
+ number_conf_file : bool, optional
125
+ If True, add a number in front of each line of the conf file. Required
126
+ to identify slurm jobs.
127
+ The default is True.
128
+
129
+ Returns
130
+ -------
131
+ None.
132
+
133
+ """
134
+ ntasks = len(dirs)
135
+ nnodes = int(np.ceil(ntasks / ncores_per_node))
136
+
137
+ if folder_conf_in_job is None:
138
+ folder_conf_in_job = os.path.dirname(file_job)
139
+ if folder_conf_in_job == "":
140
+ folder_conf_in_job = "."
141
+
142
+ with open(file_job + ".conf", "w", newline="\n") as conf_file:
143
+ if number_conf_file:
144
+ line = "{:d} {:s} {:s} {:s}\n"
145
+ else:
146
+ line = "{:s} {:s} {:s}\n"
147
+ for i in range(ntasks):
148
+ if replace_path is not None:
149
+ folder = dirs[i].replace(replace_path[0], replace_path[1])
150
+ param_file = param_files[i].replace(
151
+ replace_path[0], replace_path[1]
152
+ )
153
+ else:
154
+ folder = dirs[i]
155
+ param_file = param_files[i]
156
+ folder = format_path_linux(folder)
157
+ param_file = format_path_linux(param_file)
158
+ if number_conf_file:
159
+ line2 = line.format(i, shaltop_file, folder, param_file)
160
+ else:
161
+ line2 = line.format(shaltop_file, folder, param_file)
162
+ conf_file.write(line2)
163
+
164
+ n_hours = np.floor(max_time_hours)
165
+ n_min = (max_time_hours - n_hours) * 60
166
+ str_time = "{:02.0f}:{:02.0f}:00\n".format(n_hours, n_min)
167
+
168
+ basename = os.path.basename(file_job)
169
+ path_conf_in_job = posixpath.join(folder_conf_in_job, basename + ".conf")
170
+
171
+ with open(file_job + ".job", "w", newline="\n") as job_file:
172
+ job_file.write("#!/bin/sh\n")
173
+ job_file.write("#SBATCH -J multijob\n")
174
+ job_file.write("#SBATCH --job-name={:s}\n".format(job_name))
175
+ job_file.write("#SBATCH --output={:s}%j.out\n".format(job_name))
176
+ job_file.write("#SBATCH --partition " + partitions + "\n")
177
+ job_file.write("#SBATCH --nodes={:d}".format(nnodes) + "\n")
178
+ job_file.write("#SBATCH --ntasks={:d}".format(ntasks) + "\n")
179
+ job_file.write("#SBATCH --time={:s}\n".format(str_time))
180
+ job_file.write("\n")
181
+ job_file.write("module purge\n")
182
+ job_file.write("module load slurm\n")
183
+ job_file.write("\n")
184
+ line = "srun -n {:d} -l --multi-prog {:s}"
185
+ job_file.write(line.format(ntasks, path_conf_in_job))
186
+
187
+
76
188
  def make_simus(law, rheol_params, folder_data, folder_out, readme_file):
77
189
  """
78
190
  Write shaltop initial file for simple slope test case
@@ -92,57 +204,58 @@ def make_simus(law, rheol_params, folder_data, folder_out, readme_file):
92
204
 
93
205
  """
94
206
  # Get topography and initial mass, and write them in Shaltop format
95
- zfile = os.path.join(folder_data, 'topo.asc')
96
- mfile = os.path.join(folder_data, 'mass.asc')
207
+ zfile = os.path.join(folder_data, "topo.asc")
208
+ mfile = os.path.join(folder_data, "mass.asc")
97
209
  x, y, z, dx = tilupy.raster.read_ascii(zfile)
98
210
  _, _, m, _ = tilupy.raster.read_ascii(mfile)
99
- np.savetxt(os.path.join(folder_out, 'z.d'), z.T.flatten())
100
- np.savetxt(os.path.join(folder_out, 'm.d'), m.T.flatten())
211
+ np.savetxt(os.path.join(folder_out, "z.d"), z.T.flatten())
212
+ np.savetxt(os.path.join(folder_out, "m.d"), m.T.flatten())
101
213
 
102
214
  # Get simulation parameters from README.txt and raster .asc files
103
215
  params = tilupy.notations.readme_to_params(readme_file, README_PARAM_MATCH)
104
- params['nx'] = len(x)
105
- params['ny'] = len(y)
106
- params['per'] = dx*len(x)
107
- params['pery'] = dx*len(y)
108
- params['file_m_init'] = '../m.d'
109
- params['file_z_init'] = '../z.d'
216
+ params["nx"] = len(x)
217
+ params["ny"] = len(y)
218
+ params["per"] = dx * len(x)
219
+ params["pery"] = dx * len(y)
220
+ params["file_m_init"] = "../m.d"
221
+ params["file_z_init"] = "../z.d"
110
222
 
111
223
  # Folder for rheological law, and set params accordingly
112
224
  folder_law = os.path.join(folder_out, law)
113
- params['icomp'] = SHALTOP_LAW_ID[law]
225
+ params["icomp"] = SHALTOP_LAW_ID[law]
114
226
 
115
227
  param_names = [param for param in rheol_params]
116
228
 
117
229
  texts = tilupy.notations.make_rheol_string(rheol_params, law)
118
230
 
119
231
  # Run shaltop file
120
- run_shaltop_file = os.path.join(folder_law, 'run_shaltop.sh')
232
+ run_shaltop_file = os.path.join(folder_law, "run_shaltop.sh")
121
233
  file_txt = ""
122
234
 
123
235
  for i in range(len(rheol_params[param_names[0]])):
124
-
125
236
  simu_text = texts[i]
126
237
  for param_name in param_names:
127
238
  params[param_name] = rheol_params[param_name][i]
128
- params['folder_output'] = simu_text
239
+ params["folder_output"] = simu_text
129
240
  folder_results = os.path.join(folder_law, simu_text)
130
241
  os.makedirs(folder_results, exist_ok=True)
131
- with open(os.path.join(folder_results, '.gitignore'), 'w') as fid:
132
- fid.write('# Ignore everything in this directory')
133
- fid.write('*')
134
- fid.write('# Except this file')
135
- fid.write('!.gitignore')
136
-
137
- write_params_file(params, directory=folder_law,
138
- file_name=simu_text+'.txt')
139
- file_txt += 'start_time=`date +%s`\n'
140
- file_txt += 'shaltop "" ' + simu_text + '.txt\n'
141
- file_txt += 'end_time=`date +%s`\n'
142
- file_txt += 'elapsed_time=$(($end_time - $start_time))\n'
143
- file_txt += ('string_time="${start_time} ' +
144
- simu_text + ' ${elapsed_time}"\n')
145
- file_txt += 'echo ${string_time} >> simulation_duration.txt\n\n'
242
+ with open(os.path.join(folder_results, ".gitignore"), "w") as fid:
243
+ fid.write("# Ignore everything in this directory")
244
+ fid.write("*")
245
+ fid.write("# Except this file")
246
+ fid.write("!.gitignore")
247
+
248
+ write_params_file(
249
+ params, directory=folder_law, file_name=simu_text + ".txt"
250
+ )
251
+ file_txt += "start_time=`date +%s`\n"
252
+ file_txt += 'shaltop "" ' + simu_text + ".txt\n"
253
+ file_txt += "end_time=`date +%s`\n"
254
+ file_txt += "elapsed_time=$(($end_time - $start_time))\n"
255
+ file_txt += (
256
+ 'string_time="${start_time} ' + simu_text + ' ${elapsed_time}"\n'
257
+ )
258
+ file_txt += "echo ${string_time} >> simulation_duration.txt\n\n"
146
259
 
147
260
  with open(run_shaltop_file, "w") as fid:
148
261
  fid.write(file_txt)