tilupy 0.1.4__tar.gz → 1.0.0__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 (47) hide show
  1. {tilupy-0.1.4/src/tilupy.egg-info → tilupy-1.0.0}/PKG-INFO +10 -3
  2. {tilupy-0.1.4 → tilupy-1.0.0}/README.md +1 -1
  3. {tilupy-0.1.4 → tilupy-1.0.0}/pyproject.toml +2 -2
  4. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/calibration.py +29 -32
  5. tilupy-1.0.0/src/tilupy/cmd.py +179 -0
  6. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/initdata.py +36 -0
  7. tilupy-1.0.0/src/tilupy/make_mass.py +108 -0
  8. tilupy-1.0.0/src/tilupy/make_topo.py +415 -0
  9. tilupy-1.0.0/src/tilupy/models/shaltop/initsimus.py +261 -0
  10. tilupy-1.0.0/src/tilupy/models/shaltop/read.py +455 -0
  11. tilupy-1.0.0/src/tilupy/notations.py +402 -0
  12. tilupy-1.0.0/src/tilupy/plot.py +827 -0
  13. tilupy-1.0.0/src/tilupy/read.py +982 -0
  14. tilupy-1.0.0/src/tilupy/utils.py +159 -0
  15. {tilupy-0.1.4 → tilupy-1.0.0/src/tilupy.egg-info}/PKG-INFO +10 -3
  16. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy.egg-info/SOURCES.txt +6 -0
  17. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy.egg-info/requires.txt +1 -0
  18. tilupy-1.0.0/tests/test_generated_data.py +17 -0
  19. tilupy-1.0.0/tests/test_notations.py +68 -0
  20. tilupy-1.0.0/tests/test_read.py +130 -0
  21. tilupy-1.0.0/tests/test_read_from_simu.py +103 -0
  22. tilupy-1.0.0/tests/test_shaltop.py +126 -0
  23. tilupy-0.1.4/src/tilupy/cmd.py +0 -125
  24. tilupy-0.1.4/src/tilupy/models/shaltop/initsimus.py +0 -148
  25. tilupy-0.1.4/src/tilupy/models/shaltop/read.py +0 -300
  26. tilupy-0.1.4/src/tilupy/notations.py +0 -117
  27. tilupy-0.1.4/src/tilupy/plot.py +0 -530
  28. tilupy-0.1.4/src/tilupy/read.py +0 -400
  29. tilupy-0.1.4/src/tilupy/utils.py +0 -131
  30. tilupy-0.1.4/tests/test_shaltop.py +0 -106
  31. {tilupy-0.1.4 → tilupy-1.0.0}/LICENSE +0 -0
  32. {tilupy-0.1.4 → tilupy-1.0.0}/MANIFEST.in +0 -0
  33. {tilupy-0.1.4 → tilupy-1.0.0}/data/frankslide/rasters/Frankslide_pile.asc +0 -0
  34. {tilupy-0.1.4 → tilupy-1.0.0}/data/frankslide/rasters/Frankslide_topography.asc +0 -0
  35. {tilupy-0.1.4 → tilupy-1.0.0}/setup.cfg +0 -0
  36. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/__init__.py +0 -0
  37. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/compare.py +0 -0
  38. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/download_data.py +0 -0
  39. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/models/__init__.py +0 -0
  40. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/models/ravaflow/__init__.py +0 -0
  41. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/models/ravaflow/initsimus.py +0 -0
  42. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/models/ravaflow/read.py +0 -0
  43. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/models/shaltop/__init__.py +0 -0
  44. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy/raster.py +0 -0
  45. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy.egg-info/dependency_links.txt +0 -0
  46. {tilupy-0.1.4 → tilupy-1.0.0}/src/tilupy.egg-info/entry_points.txt +0 -0
  47. {tilupy-0.1.4 → tilupy-1.0.0}/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.4
3
+ Version: 1.0.0
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
@@ -526,10 +526,17 @@ Classifier: Programming Language :: Python
526
526
  Classifier: Programming Language :: Python :: 3
527
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.4"
9
+ version = "v1.0.0"
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,7 +18,7 @@ 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
23
  requires-python = ">=3.8"
24
24
 
@@ -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
@@ -0,0 +1,179 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Created on Wed Jun 14 18:16:45 2023
4
+
5
+ @author: peruzzetto
6
+ """
7
+
8
+ import tilupy.raster
9
+ import tilupy.read
10
+
11
+ import os
12
+ import argparse
13
+ import glob
14
+
15
+
16
+ def process_results(
17
+ fn_name,
18
+ model,
19
+ res_name,
20
+ folder=None,
21
+ param_files=None,
22
+ kwargs_read=None,
23
+ **kwargs_fn
24
+ ):
25
+ assert model is not None
26
+
27
+ if folder is None:
28
+ folder = os.getcwd()
29
+
30
+ if param_files is None:
31
+ param_files = "*.txt"
32
+
33
+ print(folder, param_files)
34
+
35
+ param_files = glob.glob(os.path.join(folder, param_files))
36
+
37
+ if len(param_files) == 0:
38
+ print("No parameter file matching param_files pattern was found")
39
+ return
40
+
41
+ if kwargs_read is None:
42
+ kwargs_read = dict()
43
+
44
+ kw_read = dict(folder_base=folder)
45
+ kw_read.update(kwargs_read)
46
+
47
+ for param_file in param_files:
48
+ print_str = "Processing simulation {:s}, {:s} {:s} ....."
49
+ print(print_str.format(param_file, fn_name, res_name))
50
+ kw_read["file_params"] = param_file
51
+ res = tilupy.read.get_results(model, **kw_read)
52
+ getattr(res, fn_name)(res_name, **kwargs_fn)
53
+
54
+
55
+ def to_raster(
56
+ model=None,
57
+ res_name="h",
58
+ param_files=None,
59
+ folder=None,
60
+ kwargs_read=None,
61
+ **kwargs
62
+ ):
63
+ kw = dict(fmt="asc")
64
+ kw.update(kwargs)
65
+
66
+ process_results(
67
+ "save",
68
+ model,
69
+ res_name,
70
+ folder=folder,
71
+ param_files=param_files,
72
+ kwargs_read=kwargs_read,
73
+ **kw
74
+ )
75
+
76
+
77
+ def plot_results(
78
+ model=None,
79
+ res_name="h",
80
+ param_files=None,
81
+ folder=None,
82
+ kwargs_read=None,
83
+ **kwargs
84
+ ):
85
+ kw = dict(save=True)
86
+ kw.update(kwargs)
87
+
88
+ process_results(
89
+ "plot",
90
+ model,
91
+ res_name,
92
+ folder=folder,
93
+ param_files=param_files,
94
+ kwargs_read=kwargs_read,
95
+ **kwargs
96
+ )
97
+
98
+
99
+ def _get_parser(prog, description):
100
+ parser = argparse.ArgumentParser(
101
+ prog=prog,
102
+ description=description,
103
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
104
+ )
105
+ parser.add_argument("model", help="Model name", type=str)
106
+ parser.add_argument(
107
+ "-n",
108
+ "--res_name",
109
+ help="Name of output, only for maps",
110
+ default="h",
111
+ type=str,
112
+ )
113
+ parser.add_argument(
114
+ "-p",
115
+ "--param_files",
116
+ help="Parameter file (globbing)",
117
+ default="*.txt",
118
+ type=str,
119
+ )
120
+ parser.add_argument(
121
+ "-f",
122
+ "--folder",
123
+ help="Root folder, default is current folder",
124
+ default=None,
125
+ type=str,
126
+ )
127
+ return parser
128
+
129
+
130
+ def _tilupy_plot():
131
+ parser = _get_parser("tilupy_plot", "Plot thin-layer simulation results")
132
+ parser.add_argument(
133
+ "--fmt",
134
+ help=("Plot output format " "(any accepted by matplotlib.savefig)"),
135
+ default="png",
136
+ type=str,
137
+ )
138
+ parser.add_argument(
139
+ "--vmin",
140
+ help=("Minimum plotted value, " "adapted to data by default"),
141
+ default=None,
142
+ type=float,
143
+ )
144
+ parser.add_argument(
145
+ "--vmax",
146
+ help=("Maximum plotted value, " "adapted to data by default"),
147
+ default=None,
148
+ type=float,
149
+ )
150
+ parser.add_argument(
151
+ "--minval_abs",
152
+ help=("Minimum plotted absolute value," " adapted to data by default"),
153
+ default=None,
154
+ type=float,
155
+ )
156
+ args = parser.parse_args()
157
+ plot_results(**vars(args))
158
+
159
+
160
+ def _tilupy_to_raster():
161
+ parser = _get_parser(
162
+ "tilupy_to_raster", "Convert simulation results to rasters"
163
+ )
164
+ parser.add_argument(
165
+ "--fmt",
166
+ help=("File output format, " "tif/tiff requires rasterio"),
167
+ default="asc",
168
+ type=str,
169
+ choices=["tif", "tiff", "txt", "asc", "ascii"],
170
+ )
171
+ args = parser.parse_args()
172
+ # plot_results(parser.model, parser.res_name)
173
+ to_raster(**vars(args))
174
+
175
+
176
+ if __name__ == "__main__":
177
+ # folder = 'd:/Documents/peruzzetto/tmp/test_shaltop/7p30e04_m3/coulomb'
178
+ # plot_results('shaltop', 'h_max', '*18p00.txt', folder=folder)
179
+ _tilupy_plot()
@@ -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