easypyram 2.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.
@@ -0,0 +1,31 @@
1
+ Copyright © 2000 Dr. Michael D. Collins
2
+ Copyright © 2017 Marcus Donnelly
3
+ Copyright © 2026 Per A. Brodtkorb
4
+
5
+ All rights reserved.
6
+
7
+ Redistribution and use in source and binary forms, with or without
8
+ modification, are permitted provided that the following conditions are met:
9
+
10
+ - Redistributions of source code must retain the above copyright notice,
11
+ this list of conditions and the following disclaimer.
12
+
13
+ - Redistributions in binary form must reproduce the above copyright notice,
14
+ this list of conditions and the following disclaimer in the documentation
15
+ and/or other materials provided with the distribution.
16
+
17
+ - Neither the name of the copyright holder nor the names of its contributors
18
+ may be used to endorse or promote products derived from this software
19
+ without specific prior written permission.
20
+
21
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
+ POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,250 @@
1
+ Metadata-Version: 2.4
2
+ Name: easypyram
3
+ Version: 2.0.0
4
+ Summary: User-friendly Python implementation of the Range-dependent Acoustic Model (RAM) for underwater acoustics
5
+ Keywords: acoustics,underwater acoustics,ocean acoustics,acoustic propagation,sound propagation,parabolic equation,RAM,PyRAM
6
+ Author-Email: "Per A. Brodtkorb" <per.andreas.brodtkorb@gmail.com>
7
+ Maintainer-Email: "Per A. Brodtkorb" <per.andreas.brodtkorb@gmail.com>
8
+ License-Expression: BSD-3-Clause
9
+ License-File: LICENSE.md
10
+ Classifier: Development Status :: 5 - Production/Stable
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Scientific/Engineering
20
+ Classifier: Topic :: Scientific/Engineering :: Physics
21
+ Project-URL: Homepage, https://github.com/pbrod/easypyram
22
+ Project-URL: Repository, https://github.com/pbrod/easypyram
23
+ Project-URL: Issues, https://github.com/pbrod/easypyram/issues
24
+ Project-URL: Changelog, https://github.com/pbrod/easypyram/blob/master/CHANGELOG.md
25
+ Requires-Python: >=3.10
26
+ Requires-Dist: numpy>=1.25
27
+ Requires-Dist: numba>=0.58
28
+ Provides-Extra: plot
29
+ Requires-Dist: matplotlib>=3.8.0; extra == "plot"
30
+ Description-Content-Type: text/markdown
31
+
32
+ # EasyPyRAM
33
+
34
+ **EasyPyRAM** is a user-friendly Python implementation of the
35
+ Range-dependent Acoustic Model (RAM) for underwater acoustic propagation.
36
+
37
+ The project builds on PyRAM while placing additional emphasis on ease of use,
38
+ sensible defaults, structured results, documentation, examples, testing, and
39
+ modern Python development practices.
40
+
41
+ EasyPyRAM aims to lower the barrier to using RAM without hiding the numerical
42
+ parameters that experienced users may need to control.
43
+
44
+ ## Background
45
+
46
+ RAM was created by Michael D. Collins at the U.S. Naval Research Laboratory.
47
+ The Python implementation is based on RAM v1.5, available from the
48
+ Ocean Acoustics Library:
49
+
50
+ https://oalib-acoustics.org/models-and-software/parabolic-equation
51
+
52
+ PyRAM was developed by Marcus Donnelly to provide a version of RAM that can be
53
+ used directly within a Python environment, such as IPython, Spyder, or Jupyter,
54
+ and that is easier to understand, extend, and integrate into other applications
55
+ than the original Fortran implementation.
56
+
57
+ The implementation is written in Python and uses Numba JIT compilation for the
58
+ computationally intensive numerical routines, providing performance comparable
59
+ to compiled native code while retaining a Python interface.
60
+
61
+ The `PyRAM` class largely follows the structure of the original RAM Fortran
62
+ implementation. Many methods correspond directly to the original Fortran
63
+ subroutines and functions and retain similar names and variable conventions.
64
+ Some Fortran routines that are unnecessary in Python have been replaced by
65
+ functionality provided by NumPy and other standard scientific Python tools.
66
+
67
+ As in PyRAM, sound-speed profile updates with range are decoupled from seabed
68
+ parameter updates. This provides greater flexibility when environmental data
69
+ come from different sources or have different horizontal sampling intervals.
70
+
71
+ ## Why EasyPyRAM?
72
+
73
+ EasyPyRAM retains the RAM numerical model and the core design of PyRAM while
74
+ providing a more accessible interface for both new and experienced users.
75
+
76
+ In particular, EasyPyRAM provides:
77
+
78
+ - sensible default numerical parameters that allow users to get started
79
+ without first having to tune the RAM computational grid;
80
+ - structured, typed results with convenient access to transmission loss,
81
+ complex pressure, ranges, depths, and model metadata;
82
+ - built-in sound-speed profile helpers, including Munk and idealized Arctic
83
+ profiles;
84
+ - practical examples demonstrating typical underwater-acoustic propagation
85
+ problems;
86
+ - expanded documentation covering model configuration, numerical accuracy,
87
+ stability, and parameter selection;
88
+ - NumPy-based inputs and outputs for straightforward integration with the
89
+ scientific Python ecosystem;
90
+ - multiprocessing support for running multiple frequencies or acoustic
91
+ environments in parallel;
92
+ - modern Python packaging, testing, static type checking, and continuous
93
+ integration.
94
+
95
+ The default range and depth steps are automatically selected from the acoustic
96
+ wavelength, providing a practical starting point for new users. Experienced
97
+ users can override these and the other numerical parameters when finer control
98
+ is required.
99
+
100
+ ## Installation
101
+
102
+ EasyPyRAM requires Python 3.10 or later.
103
+
104
+ Install the latest release from PyPI:
105
+
106
+ ```bash
107
+ python -m pip install easypyram
108
+ ```
109
+
110
+ To include the optional plotting dependencies used by the examples:
111
+
112
+ ```bash
113
+ python -m pip install "easypyram[plot]"
114
+ ```
115
+
116
+ To install the latest development version directly from GitHub:
117
+
118
+ ```bash
119
+ python -m pip install "git+https://github.com/pbrod/easypyram.git"
120
+ ```
121
+
122
+ ## Quick Start
123
+
124
+ The following example calculates transmission loss for a simple
125
+ range-independent environment:
126
+
127
+ ```python
128
+ import numpy as np
129
+
130
+ from easypyram import PyRAM
131
+
132
+ pyram = PyRAM(
133
+ freq=50.0,
134
+ zs=50.0,
135
+ zr=50.0,
136
+ z_ss=np.array([0.0, 100.0, 400.0]),
137
+ rp_ss=np.array([0.0]),
138
+ cw=np.array(
139
+ [
140
+ [1480.0],
141
+ [1520.0],
142
+ [1530.0],
143
+ ]
144
+ ),
145
+ z_sb=np.array([0.0]),
146
+ rp_sb=np.array([0.0]),
147
+ cb=np.array([[1700.0]]),
148
+ rhob=np.array([[1.5]]),
149
+ attn=np.array([[0.5]]),
150
+ rbzb=np.array(
151
+ [
152
+ [0.0, 400.0],
153
+ [50_000.0, 400.0],
154
+ ]
155
+ ),
156
+ rmax=50_000.0,
157
+ )
158
+
159
+ result = pyram.run()
160
+ ```
161
+
162
+ EasyPyRAM returns a structured `PyRAMResults` object. Model outputs are
163
+ therefore directly available as attributes:
164
+
165
+ ```python
166
+ result.ranges
167
+ result.depths
168
+
169
+ result.loss_line
170
+ result.loss_grid
171
+
172
+ result.pressure_line
173
+ result.pressure_grid
174
+
175
+ result.c0
176
+ result.proc_time
177
+ ```
178
+
179
+ For example, transmission loss at the receiver depth can be plotted with:
180
+
181
+ ```python
182
+ import matplotlib.pyplot as plt
183
+
184
+ plt.plot(result.ranges / 1000.0, result.loss_line)
185
+ plt.xlabel("Range [km]")
186
+ plt.ylabel("Transmission loss [dB]")
187
+ plt.grid()
188
+ plt.show()
189
+ ```
190
+
191
+ ## Sound-Speed Profiles
192
+
193
+ EasyPyRAM provides helpers for constructing representative sound-speed
194
+ profiles.
195
+
196
+ ### Munk profile
197
+
198
+ The canonical Munk deep-ocean sound-speed profile can be evaluated at arbitrary
199
+ depths:
200
+
201
+ ```python
202
+ import numpy as np
203
+
204
+ from easypyram import munk_profile
205
+
206
+ depth = np.arange(0.0, 5000.0, 10.0)
207
+ sound_speed = munk_profile(depth)
208
+ ```
209
+
210
+ ### Arctic profile
211
+
212
+ An idealized Arctic profile is also provided:
213
+
214
+ ```python
215
+ from easypyram import arctic_profile
216
+
217
+ sound_speed = arctic_profile(depth)
218
+ ```
219
+
220
+ The profiles can be compared directly:
221
+
222
+ ```python
223
+ import matplotlib.pyplot as plt
224
+ import numpy as np
225
+
226
+ from easypyram import arctic_profile, munk_profile
227
+
228
+ depth = np.arange(0.0, 2000.0)
229
+
230
+ plt.plot(munk_profile(depth), depth, label="Munk")
231
+ plt.plot(arctic_profile(depth), depth, label="Arctic")
232
+
233
+ plt.xlabel("Sound speed [m/s]")
234
+ plt.ylabel("Depth [m]")
235
+ plt.gca().invert_yaxis()
236
+ plt.legend()
237
+ plt.show()
238
+ ```
239
+
240
+ ## Relationship to RAM and PyRAM
241
+
242
+ RAM was developed by Michael D. Collins at the U.S. Naval Research Laboratory.
243
+
244
+ PyRAM was developed by Marcus Donnelly as a Python adaptation of RAM.
245
+
246
+ EasyPyRAM is derived from PyRAM and is independently maintained, with an
247
+ emphasis on ease of use, sensible defaults, structured results, documentation,
248
+ examples, and modern Python development practices.
249
+  
250
+ EasyPyRAM is not an official version of RAM or PyRAM.
@@ -0,0 +1,219 @@
1
+ # EasyPyRAM
2
+
3
+ **EasyPyRAM** is a user-friendly Python implementation of the
4
+ Range-dependent Acoustic Model (RAM) for underwater acoustic propagation.
5
+
6
+ The project builds on PyRAM while placing additional emphasis on ease of use,
7
+ sensible defaults, structured results, documentation, examples, testing, and
8
+ modern Python development practices.
9
+
10
+ EasyPyRAM aims to lower the barrier to using RAM without hiding the numerical
11
+ parameters that experienced users may need to control.
12
+
13
+ ## Background
14
+
15
+ RAM was created by Michael D. Collins at the U.S. Naval Research Laboratory.
16
+ The Python implementation is based on RAM v1.5, available from the
17
+ Ocean Acoustics Library:
18
+
19
+ https://oalib-acoustics.org/models-and-software/parabolic-equation
20
+
21
+ PyRAM was developed by Marcus Donnelly to provide a version of RAM that can be
22
+ used directly within a Python environment, such as IPython, Spyder, or Jupyter,
23
+ and that is easier to understand, extend, and integrate into other applications
24
+ than the original Fortran implementation.
25
+
26
+ The implementation is written in Python and uses Numba JIT compilation for the
27
+ computationally intensive numerical routines, providing performance comparable
28
+ to compiled native code while retaining a Python interface.
29
+
30
+ The `PyRAM` class largely follows the structure of the original RAM Fortran
31
+ implementation. Many methods correspond directly to the original Fortran
32
+ subroutines and functions and retain similar names and variable conventions.
33
+ Some Fortran routines that are unnecessary in Python have been replaced by
34
+ functionality provided by NumPy and other standard scientific Python tools.
35
+
36
+ As in PyRAM, sound-speed profile updates with range are decoupled from seabed
37
+ parameter updates. This provides greater flexibility when environmental data
38
+ come from different sources or have different horizontal sampling intervals.
39
+
40
+ ## Why EasyPyRAM?
41
+
42
+ EasyPyRAM retains the RAM numerical model and the core design of PyRAM while
43
+ providing a more accessible interface for both new and experienced users.
44
+
45
+ In particular, EasyPyRAM provides:
46
+
47
+ - sensible default numerical parameters that allow users to get started
48
+ without first having to tune the RAM computational grid;
49
+ - structured, typed results with convenient access to transmission loss,
50
+ complex pressure, ranges, depths, and model metadata;
51
+ - built-in sound-speed profile helpers, including Munk and idealized Arctic
52
+ profiles;
53
+ - practical examples demonstrating typical underwater-acoustic propagation
54
+ problems;
55
+ - expanded documentation covering model configuration, numerical accuracy,
56
+ stability, and parameter selection;
57
+ - NumPy-based inputs and outputs for straightforward integration with the
58
+ scientific Python ecosystem;
59
+ - multiprocessing support for running multiple frequencies or acoustic
60
+ environments in parallel;
61
+ - modern Python packaging, testing, static type checking, and continuous
62
+ integration.
63
+
64
+ The default range and depth steps are automatically selected from the acoustic
65
+ wavelength, providing a practical starting point for new users. Experienced
66
+ users can override these and the other numerical parameters when finer control
67
+ is required.
68
+
69
+ ## Installation
70
+
71
+ EasyPyRAM requires Python 3.10 or later.
72
+
73
+ Install the latest release from PyPI:
74
+
75
+ ```bash
76
+ python -m pip install easypyram
77
+ ```
78
+
79
+ To include the optional plotting dependencies used by the examples:
80
+
81
+ ```bash
82
+ python -m pip install "easypyram[plot]"
83
+ ```
84
+
85
+ To install the latest development version directly from GitHub:
86
+
87
+ ```bash
88
+ python -m pip install "git+https://github.com/pbrod/easypyram.git"
89
+ ```
90
+
91
+ ## Quick Start
92
+
93
+ The following example calculates transmission loss for a simple
94
+ range-independent environment:
95
+
96
+ ```python
97
+ import numpy as np
98
+
99
+ from easypyram import PyRAM
100
+
101
+ pyram = PyRAM(
102
+ freq=50.0,
103
+ zs=50.0,
104
+ zr=50.0,
105
+ z_ss=np.array([0.0, 100.0, 400.0]),
106
+ rp_ss=np.array([0.0]),
107
+ cw=np.array(
108
+ [
109
+ [1480.0],
110
+ [1520.0],
111
+ [1530.0],
112
+ ]
113
+ ),
114
+ z_sb=np.array([0.0]),
115
+ rp_sb=np.array([0.0]),
116
+ cb=np.array([[1700.0]]),
117
+ rhob=np.array([[1.5]]),
118
+ attn=np.array([[0.5]]),
119
+ rbzb=np.array(
120
+ [
121
+ [0.0, 400.0],
122
+ [50_000.0, 400.0],
123
+ ]
124
+ ),
125
+ rmax=50_000.0,
126
+ )
127
+
128
+ result = pyram.run()
129
+ ```
130
+
131
+ EasyPyRAM returns a structured `PyRAMResults` object. Model outputs are
132
+ therefore directly available as attributes:
133
+
134
+ ```python
135
+ result.ranges
136
+ result.depths
137
+
138
+ result.loss_line
139
+ result.loss_grid
140
+
141
+ result.pressure_line
142
+ result.pressure_grid
143
+
144
+ result.c0
145
+ result.proc_time
146
+ ```
147
+
148
+ For example, transmission loss at the receiver depth can be plotted with:
149
+
150
+ ```python
151
+ import matplotlib.pyplot as plt
152
+
153
+ plt.plot(result.ranges / 1000.0, result.loss_line)
154
+ plt.xlabel("Range [km]")
155
+ plt.ylabel("Transmission loss [dB]")
156
+ plt.grid()
157
+ plt.show()
158
+ ```
159
+
160
+ ## Sound-Speed Profiles
161
+
162
+ EasyPyRAM provides helpers for constructing representative sound-speed
163
+ profiles.
164
+
165
+ ### Munk profile
166
+
167
+ The canonical Munk deep-ocean sound-speed profile can be evaluated at arbitrary
168
+ depths:
169
+
170
+ ```python
171
+ import numpy as np
172
+
173
+ from easypyram import munk_profile
174
+
175
+ depth = np.arange(0.0, 5000.0, 10.0)
176
+ sound_speed = munk_profile(depth)
177
+ ```
178
+
179
+ ### Arctic profile
180
+
181
+ An idealized Arctic profile is also provided:
182
+
183
+ ```python
184
+ from easypyram import arctic_profile
185
+
186
+ sound_speed = arctic_profile(depth)
187
+ ```
188
+
189
+ The profiles can be compared directly:
190
+
191
+ ```python
192
+ import matplotlib.pyplot as plt
193
+ import numpy as np
194
+
195
+ from easypyram import arctic_profile, munk_profile
196
+
197
+ depth = np.arange(0.0, 2000.0)
198
+
199
+ plt.plot(munk_profile(depth), depth, label="Munk")
200
+ plt.plot(arctic_profile(depth), depth, label="Arctic")
201
+
202
+ plt.xlabel("Sound speed [m/s]")
203
+ plt.ylabel("Depth [m]")
204
+ plt.gca().invert_yaxis()
205
+ plt.legend()
206
+ plt.show()
207
+ ```
208
+
209
+ ## Relationship to RAM and PyRAM
210
+
211
+ RAM was developed by Michael D. Collins at the U.S. Naval Research Laboratory.
212
+
213
+ PyRAM was developed by Marcus Donnelly as a Python adaptation of RAM.
214
+
215
+ EasyPyRAM is derived from PyRAM and is independently maintained, with an
216
+ emphasis on ease of use, sensible defaults, structured results, documentation,
217
+ examples, and modern Python development practices.
218
+  
219
+ EasyPyRAM is not an official version of RAM or PyRAM.
@@ -0,0 +1,163 @@
1
+ [project]
2
+ name = "easypyram"
3
+ dynamic = []
4
+ description = "User-friendly Python implementation of the Range-dependent Acoustic Model (RAM) for underwater acoustics"
5
+ authors = [
6
+ { name = "Per A. Brodtkorb", email = "per.andreas.brodtkorb@gmail.com" },
7
+ ]
8
+ maintainers = [
9
+ { name = "Per A. Brodtkorb", email = "per.andreas.brodtkorb@gmail.com" },
10
+ ]
11
+ readme = "README.md"
12
+ license = "BSD-3-Clause"
13
+ license-files = [
14
+ "LICENSE.md",
15
+ ]
16
+ classifiers = [
17
+ "Development Status :: 5 - Production/Stable",
18
+ "Intended Audience :: Science/Research",
19
+ "Intended Audience :: Developers",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.10",
22
+ "Programming Language :: Python :: 3.11",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
26
+ "Topic :: Scientific/Engineering",
27
+ "Topic :: Scientific/Engineering :: Physics",
28
+ ]
29
+ keywords = [
30
+ "acoustics",
31
+ "underwater acoustics",
32
+ "ocean acoustics",
33
+ "acoustic propagation",
34
+ "sound propagation",
35
+ "parabolic equation",
36
+ "RAM",
37
+ "PyRAM",
38
+ ]
39
+ requires-python = ">=3.10"
40
+ dependencies = [
41
+ "numpy>=1.25",
42
+ "numba>=0.58",
43
+ ]
44
+ version = "2.0.0"
45
+
46
+ [project.urls]
47
+ Homepage = "https://github.com/pbrod/easypyram"
48
+ Repository = "https://github.com/pbrod/easypyram"
49
+ Issues = "https://github.com/pbrod/easypyram/issues"
50
+ Changelog = "https://github.com/pbrod/easypyram/blob/master/CHANGELOG.md"
51
+
52
+ [project.optional-dependencies]
53
+ plot = [
54
+ "matplotlib>=3.8.0",
55
+ ]
56
+
57
+ [dependency-groups]
58
+ test = [
59
+ "matplotlib>=3.8.0",
60
+ "mypy>=1.11.2",
61
+ "pytest>=8.0",
62
+ "ruff>=0.12",
63
+ ]
64
+ release = [
65
+ "git-cliff>=2.6.1",
66
+ "pdm-bump>=0.9.8",
67
+ ]
68
+
69
+ [tool.mypy]
70
+ strict = true
71
+
72
+ [tool.ruff]
73
+ line-length = 110
74
+
75
+ [tool.ruff.lint]
76
+ select = [
77
+ "B",
78
+ "C4",
79
+ "E4",
80
+ "E7",
81
+ "E9",
82
+ "E501",
83
+ "F",
84
+ "I",
85
+ "Q",
86
+ "UP",
87
+ ]
88
+ ignore = [
89
+ "D417",
90
+ ]
91
+
92
+ [tool.ruff.lint.pydocstyle]
93
+ convention = "numpy"
94
+
95
+ [tool.ruff.format]
96
+ docstring-code-line-length = 100
97
+
98
+ [tool.pytest.ini_options]
99
+ markers = [
100
+ "slow: marks tests as slow (time-consuming)",
101
+ "benchmark: marks tests used for benchmarking",
102
+ ]
103
+ doctest_optionflags = [
104
+ "NORMALIZE_WHITESPACE",
105
+ "IGNORE_EXCEPTION_DETAIL",
106
+ "ELLIPSIS",
107
+ ]
108
+ addopts = "-rsxXf"
109
+ testpaths = [
110
+ "src",
111
+ ]
112
+
113
+ [tool.pdm]
114
+ distribution = true
115
+
116
+ [tool.pdm.resolution]
117
+ allow-prereleases = true
118
+
119
+ [tool.pdm.version]
120
+ source = "file"
121
+ path = "src/easypyram/__init__.py"
122
+
123
+ [tool.pdm.scripts]
124
+ lock = "pdm lock -dG all"
125
+ lock-py314 = "pdm lock -L pdm.lock314 --python 3.14 --strategy no_direct_minimal_versions -dG all"
126
+ format = "ruff format ./src/"
127
+ check-format = "ruff format --check ./src/"
128
+ check-style = "ruff check ./src/"
129
+ check-types = "mypy ./src/"
130
+ show-next-version = "git-cliff --bumped-version"
131
+ show-next-changelog = "git-cliff"
132
+ append-changelog = "git-cliff --unreleased --prepend CHANGELOG.md"
133
+
134
+ [tool.pdm.scripts.lock-all]
135
+ composite = [
136
+ "lock",
137
+ "lock-py314",
138
+ ]
139
+
140
+ [tool.pdm.scripts.test]
141
+ cmd = "pytest"
142
+
143
+ [tool.pdm.scripts.test.env]
144
+ MPLBACKEND = "Agg"
145
+
146
+ [tool.pdm.scripts.all-tests]
147
+ composite = [
148
+ "check-format",
149
+ "check-style",
150
+ "check-types",
151
+ "test",
152
+ ]
153
+
154
+ [tool.pdm.scripts.prepare-release]
155
+ composite = [
156
+ "append-changelog",
157
+ ]
158
+
159
+ [build-system]
160
+ requires = [
161
+ "pdm-backend",
162
+ ]
163
+ build-backend = "pdm.backend"