1515__doctest_skip__ = ["grdgradient" ]
1616
1717
18+ def _alias_option_N ( # noqa: N802
19+ normalize = False ,
20+ norm_amp = None ,
21+ norm_ambient = None ,
22+ norm_sigma = None ,
23+ norm_offset = None ,
24+ ):
25+ """
26+ Helper function to create the alias for the -N option.
27+
28+ Examples
29+ --------
30+ >>> def parse(**kwargs):
31+ ... return AliasSystem(N=_alias_option_N(**kwargs)).get("N")
32+ >>> parse(normalize=True)
33+ ''
34+ >>> parse(normalize="laplace")
35+ 'e'
36+ >>> parse(normalize="cauchy")
37+ 't'
38+ >>> parse(
39+ ... normalize="laplace",
40+ ... norm_amp=2,
41+ ... norm_offset=10,
42+ ... norm_sigma=0.5,
43+ ... norm_ambient=0.1,
44+ ... )
45+ 'e2+a0.1+s0.5+o10'
46+ >>> # Check for backward compatibility with old syntax
47+ >>> parse(normalize="e2+a0.2+s0.5+o10")
48+ 'e2+a0.2+s0.5+o10'
49+ """
50+ _normalize_mapping = {"laplace" : "e" , "cauchy" : "t" }
51+ # Check for old syntax for normalize
52+ if isinstance (normalize , str ) and normalize not in _normalize_mapping :
53+ if any (
54+ v is not None and v is not False
55+ for v in [norm_amp , norm_ambient , norm_sigma , norm_offset ]
56+ ):
57+ msg = (
58+ "Parameter 'normalize' using old syntax with raw GMT CLI string "
59+ "conflicts with parameters 'norm_amp', 'norm_ambient', 'norm_sigma', "
60+ "or 'norm_offset'."
61+ )
62+ raise GMTInvalidInput (msg )
63+ _normalize_mapping = None
64+
65+ return [
66+ Alias (normalize , name = "normalize" , mapping = _normalize_mapping ),
67+ Alias (norm_amp , name = "norm_amp" ),
68+ Alias (norm_ambient , name = "norm_ambient" , prefix = "+a" ),
69+ Alias (norm_sigma , name = "norm_sigma" , prefix = "+s" ),
70+ Alias (norm_offset , name = "norm_offset" , prefix = "+o" ),
71+ ]
72+
73+
1874@fmt_docstring
19- @use_alias (
20- D = "direction" ,
21- N = "normalize" ,
22- Q = "tiles" ,
23- S = "slope_file" ,
24- f = "coltypes" ,
25- n = "interpolation" ,
26- )
27- def grdgradient (
75+ @use_alias (D = "direction" , Q = "tiles" , S = "slope_file" , f = "coltypes" , n = "interpolation" )
76+ def grdgradient ( # noqa: PLR0913
2877 grid : PathLike | xr .DataArray ,
2978 outgrid : PathLike | None = None ,
3079 azimuth : float | Sequence [float ] | None = None ,
3180 radiance : Sequence [float ] | str | None = None ,
81+ normalize : Literal ["laplace" , "cachy" ] | bool = False ,
82+ norm_amp : float | None = None ,
83+ norm_ambient : float | None = None ,
84+ norm_sigma : float | None = None ,
85+ norm_offset : float | None = None ,
3286 region : Sequence [float | str ] | str | None = None ,
3387 verbose : Literal ["quiet" , "error" , "warning" , "timing" , "info" , "compat" , "debug" ]
3488 | bool = False ,
@@ -44,6 +98,8 @@ def grdgradient(
4498
4599 $aliases
46100 - A = azimuth
101+ - N = normalize, norm_amp, **+a**: norm_ambient, **+s**: norm_sigma,
102+ **+o**: norm_offset
47103 - E = radiance
48104 - R = region
49105 - V = verbose
@@ -100,31 +156,37 @@ def grdgradient(
100156 algorithm; in this case *azim* and *elev* are hardwired to 315
101157 and 45 degrees. This means that even if you provide other values
102158 they will be ignored.).
103- normalize : str or bool
104- [**e**\|\ **t**][*amp*][**+a**\ *ambient*][**+s**\ *sigma*]\
105- [**+o**\ *offset*].
106- The actual gradients :math:`g` are offset and scaled to produce
107- normalized gradients :math:`g_n` with a maximum output magnitude of
108- *amp*. If *amp* is not given, default *amp* = 1. If *offset* is not
109- given, it is set to the average of :math:`g`. The following forms are
110- supported:
111-
112- - **True**: Normalize using math:`g_n = \mbox{amp}\
113- (\frac{g - \mbox{offset}}{max(|g - \mbox{offset}|)})`
114- - **e**: Normalize using a cumulative Laplace distribution yielding:
115- :math:`g_n = \mbox{amp}(1 - \
116- \exp{(\sqrt{2}\frac{g - \mbox{offset}}{\sigma}))}`, where
117- :math:`\sigma` is estimated using the L1 norm of
118- :math:`(g - \mbox{offset})` if it is not given.
119- - **t**: Normalize using a cumulative Cauchy distribution yielding:
120- :math:`g_n = \
121- \frac{2(\mbox{amp})}{\pi}(\tan^{-1}(\frac{g - \
122- \mbox{offset}}{\sigma}))` where :math:`\sigma` is estimated
123- using the L2 norm of :math:`(g - \mbox{offset})` if it is not
124- given.
125-
126- As a final option, you may add **+a**\ *ambient* to add *ambient* to
127- all nodes after gradient calculations are completed.
159+ normalize
160+ Normalize the output gradients. Valid values are:
161+
162+ - ``False``: No normalization is done [Default].
163+ - ``True``: Normalize using max absolute value.
164+ - ``"laplace"``: Normalize using cumulative Laplace distribution.
165+ - ``"cauchy"``: Normalize using cumulative Cauchy distribution.
166+
167+ The normalization process is controlled via the additional parameters
168+ ``norm_amp``, ``norm_ambient``, ``norm_sigma``, and ``norm_offset``.
169+
170+ Let :math:`g` denote the actual gradients, :math:`g_n` the normalized gradients,
171+ :math:`a` the maximum output magnitude (``norm_amp``), :math:`o` the offset
172+ value (``norm_offset``), and :math:`\sigma` the sigma value (``norm_sigma``).
173+ The normalization is computed as follows:
174+
175+ - ``True``: :math:`g_n = a (\frac{g - o}{\max(|g - o|)})`
176+ - ``"laplace"``: :math:`g_n = a(1 - \exp(\sqrt{2}\frac{g - o}{\sigma}))`
177+ - ``"cauchy"``: :math:`g_n = \frac{2a}{\pi}\arctan(\frac{g - o}{\sigma})`
178+ norm_amp
179+ Set the maximum output magnitude [Default is 1].
180+ norm_ambient
181+ The ambient value to add to all nodes after gradient calculations are completed
182+ [Default is 0].
183+ norm_offset
184+ The offset value used in the normalization. If not given, it is set to the
185+ average of :math:`g`.
186+ norm_sigma
187+ The *sigma* value used in the Laplace or Cauchy normalization. If not given,
188+ it is estimated from the L1 norm of :math:`g-o` for Laplace or the L2 norm of
189+ :math:`g-o` for Cauchy.
128190 tiles : str
129191 **c**\|\ **r**\|\ **R**.
130192 Control how normalization via ``normalize`` is carried out. When
@@ -181,6 +243,13 @@ def grdgradient(
181243 aliasdict = AliasSystem (
182244 A = Alias (azimuth , name = "azimuth" , sep = "/" , size = 2 ),
183245 E = Alias (radiance , name = "radiance" , sep = "/" , size = 2 ),
246+ N = _alias_option_N (
247+ normalize ,
248+ norm_amp ,
249+ norm_ambient ,
250+ norm_sigma ,
251+ norm_offset ,
252+ ),
184253 ).add_common (
185254 R = region ,
186255 V = verbose ,
0 commit comments