planetmodel 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.
- planetmodel-1.0.0/LICENSE +28 -0
- planetmodel-1.0.0/PKG-INFO +161 -0
- planetmodel-1.0.0/README.md +125 -0
- planetmodel-1.0.0/pyproject.toml +82 -0
- planetmodel-1.0.0/src/planetmodel/__init__.py +208 -0
- planetmodel-1.0.0/src/planetmodel/behaviours.py +286 -0
- planetmodel-1.0.0/src/planetmodel/catalogue.py +274 -0
- planetmodel-1.0.0/src/planetmodel/character.py +146 -0
- planetmodel-1.0.0/src/planetmodel/deck.py +447 -0
- planetmodel-1.0.0/src/planetmodel/displacement.py +312 -0
- planetmodel-1.0.0/src/planetmodel/fields.py +599 -0
- planetmodel-1.0.0/src/planetmodel/frames.py +232 -0
- planetmodel-1.0.0/src/planetmodel/geometry.py +420 -0
- planetmodel-1.0.0/src/planetmodel/harmonics.py +184 -0
- planetmodel-1.0.0/src/planetmodel/layerfunction.py +503 -0
- planetmodel-1.0.0/src/planetmodel/loading/__init__.py +41 -0
- planetmodel-1.0.0/src/planetmodel/loading/assembly.py +391 -0
- planetmodel-1.0.0/src/planetmodel/loading/love.py +342 -0
- planetmodel-1.0.0/src/planetmodel/loading/material.py +184 -0
- planetmodel-1.0.0/src/planetmodel/mapping.py +512 -0
- planetmodel-1.0.0/src/planetmodel/materials.py +465 -0
- planetmodel-1.0.0/src/planetmodel/mesh1d/__init__.py +8 -0
- planetmodel-1.0.0/src/planetmodel/mesh1d/gll.py +81 -0
- planetmodel-1.0.0/src/planetmodel/mesh1d/gravity.py +152 -0
- planetmodel-1.0.0/src/planetmodel/mesh1d/mesh.py +266 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/__init__.py +41 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/_geometry.py +138 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/_orient.py +228 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/_session.py +76 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/_sizing.py +144 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/_tagging.py +201 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/_validate.py +134 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/_writer.py +90 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/export.py +514 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/layered.py +202 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/manifest.py +547 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/offset.py +246 -0
- planetmodel-1.0.0/src/planetmodel/mesh3d/spec.py +400 -0
- planetmodel-1.0.0/src/planetmodel/model.py +471 -0
- planetmodel-1.0.0/src/planetmodel/plotting.py +99 -0
- planetmodel-1.0.0/src/planetmodel/pushforward.py +322 -0
- planetmodel-1.0.0/src/planetmodel/randomfield/__init__.py +28 -0
- planetmodel-1.0.0/src/planetmodel/randomfield/fields.py +514 -0
- planetmodel-1.0.0/src/planetmodel/randomfield/operator.py +385 -0
- planetmodel-1.0.0/src/planetmodel/rheology.py +173 -0
- planetmodel-1.0.0/src/planetmodel/sampling.py +434 -0
- planetmodel-1.0.0/src/planetmodel/skeleton.py +285 -0
- planetmodel-1.0.0/src/planetmodel/testing.py +634 -0
- planetmodel-1.0.0/src/planetmodel/units.py +204 -0
- planetmodel-1.0.0/src/planetmodel/vocabulary.py +117 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026, David Al-Attar
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: planetmodel
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Spherically layered planetary models: reference bodies, fields, mappings and meshes
|
|
5
|
+
License-Expression: BSD-3-Clause
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: geophysics,seismology,planetary models,PREM,spectral elements,meshing
|
|
8
|
+
Author: David Al-Attar
|
|
9
|
+
Author-email: da380@cam.ac.uk
|
|
10
|
+
Requires-Python: >=3.12
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
17
|
+
Provides-Extra: harmonics
|
|
18
|
+
Provides-Extra: meshing
|
|
19
|
+
Provides-Extra: mfem
|
|
20
|
+
Provides-Extra: netcdf
|
|
21
|
+
Provides-Extra: notebook
|
|
22
|
+
Provides-Extra: plot
|
|
23
|
+
Requires-Dist: ducc0 (>=0.41) ; extra == "harmonics"
|
|
24
|
+
Requires-Dist: gmsh (>=4.13) ; extra == "meshing"
|
|
25
|
+
Requires-Dist: ipykernel (>=6.29) ; extra == "notebook"
|
|
26
|
+
Requires-Dist: matplotlib (>=3.11,<4) ; extra == "plot"
|
|
27
|
+
Requires-Dist: mfem (>=4.8) ; extra == "mfem"
|
|
28
|
+
Requires-Dist: netCDF4 (>=1.7) ; extra == "netcdf"
|
|
29
|
+
Requires-Dist: numpy (>=2.5,<3)
|
|
30
|
+
Requires-Dist: pyshtools (>=4.14) ; extra == "harmonics"
|
|
31
|
+
Requires-Dist: scipy (>=1.18,<2)
|
|
32
|
+
Project-URL: Homepage, https://github.com/da380/planetmodel
|
|
33
|
+
Project-URL: Repository, https://github.com/da380/planetmodel
|
|
34
|
+
Description-Content-Type: text/markdown
|
|
35
|
+
|
|
36
|
+
# planetmodel
|
|
37
|
+
|
|
38
|
+
Spherically layered planetary models: a skeleton of boundary radii, a
|
|
39
|
+
geometry that places it in the physical world through one continuous
|
|
40
|
+
mapping, fields on each layer, and the meshes that hand a model to a
|
|
41
|
+
solver.
|
|
42
|
+
|
|
43
|
+
The library covers the skeleton, the geometry and its mappings; fields
|
|
44
|
+
on one interval with an exact polynomial algebra; the model with its
|
|
45
|
+
units, named model types (PREM from its polynomials, simple layered
|
|
46
|
+
models, any mineos deck) and the mixins that complete them with moduli,
|
|
47
|
+
velocities, gravity and linear rheologies; a radial spectral-element
|
|
48
|
+
mesh; 2D and 3D meshes via gmsh with a manifest and export to MFEM; and
|
|
49
|
+
two sub-packages that consume the radial mesh: `planetmodel.loading`
|
|
50
|
+
solves the loading and tidal problem and gives Love numbers, and
|
|
51
|
+
`planetmodel.randomfield` draws Matern random fields on balls, annuli
|
|
52
|
+
and layers. A netCDF file for 3D models is next.
|
|
53
|
+
|
|
54
|
+
## The ideas
|
|
55
|
+
|
|
56
|
+
**A skeleton.** A strictly increasing list of boundary radii, possibly
|
|
57
|
+
starting above zero for a shell. It answers geometric questions
|
|
58
|
+
(intervals, where a radius lies, with the two sides of a boundary left to
|
|
59
|
+
the caller) and supports surgery: refine, truncate, hollow, extend,
|
|
60
|
+
coarsen.
|
|
61
|
+
|
|
62
|
+
**A geometry.** A skeleton, one mapping from the reference ball to the
|
|
63
|
+
physical body, and the names of layers and interfaces. The mapping must
|
|
64
|
+
be orientation-preserving, continuous, and kinked only on skeleton
|
|
65
|
+
boundaries; a geometry checks those invariants when it is built. The
|
|
66
|
+
shipped mapping is the radial stretch `m(X) = (r + h) e_r` driven by any
|
|
67
|
+
callable `h(r, theta, phi)`, with closed forms for its deformation
|
|
68
|
+
gradient, Jacobian, validity, inverse and linearisation; any object with
|
|
69
|
+
`__call__`, `deformation_gradient` and `jacobian` is a mapping.
|
|
70
|
+
|
|
71
|
+
**A field on one interval.** Data on one layer: an interval, a character
|
|
72
|
+
(the tensor rank and weight that say how it transforms), a name, and
|
|
73
|
+
`evaluate(r, theta, phi, *, frame)` giving components in the local
|
|
74
|
+
spherical frame or in Cartesian ones. A discontinuity is two layers
|
|
75
|
+
asked separately. Radial fields sit on layer functions whose algebra is
|
|
76
|
+
exact on polynomials, so PREM's moduli `rho v^2` are exact polynomials;
|
|
77
|
+
analytic formulas, pointwise compositions, and fields pushed forward
|
|
78
|
+
through a mapping are fields too. A field may be complex-valued, which
|
|
79
|
+
is what a model frozen at a frequency holds.
|
|
80
|
+
|
|
81
|
+
**One model class.** A geometry with a bag of fields on every layer.
|
|
82
|
+
What a name means comes from the shipped vocabulary or the specs a model
|
|
83
|
+
is given. A model type (`PREM`, `LayeredIsotropicElastic`, `MineosModel`,
|
|
84
|
+
or your own) is a class derived from `Model` alone; the mixins of
|
|
85
|
+
`planetmodel.behaviours` add the shared derivations as methods, written
|
|
86
|
+
once as free functions: the Love moduli beside the velocities, the
|
|
87
|
+
elastic tensor and its Voigt average, gravity, and the constant-Q and
|
|
88
|
+
Maxwell rheologies frozen at a frequency.
|
|
89
|
+
|
|
90
|
+
**Units in one place.** The model's `Scales` say what one stored unit
|
|
91
|
+
is in SI, and `converted` re-expresses the whole model by name, exactly
|
|
92
|
+
for polynomials; `G` is read in the model's units. Nothing else names a
|
|
93
|
+
unit: radii are numbers, every tolerance is relative, and the meshers
|
|
94
|
+
hand the geometry's numbers to gmsh unchanged.
|
|
95
|
+
|
|
96
|
+
**Two meshers.** `planetmodel.mesh1d` lays Gauss-Lobatto-Legendre
|
|
97
|
+
elements along the radius with every skeleton boundary an element
|
|
98
|
+
boundary, evaluates a model's fields and gravity on its nodes, and
|
|
99
|
+
samples a model on an angular grid. `planetmodel.mesh3d` meshes a
|
|
100
|
+
geometry, full or hollow, in 2D or 3D, with shells outside it, writes a
|
|
101
|
+
JSON manifest saying what every attribute means, and exports the mesh,
|
|
102
|
+
the mapping's displacement and the model's fields to MFEM.
|
|
103
|
+
|
|
104
|
+
**Executable contracts.** `planetmodel.testing` holds one `check_*`
|
|
105
|
+
function per protocol; the shipped implementations and yours are held to
|
|
106
|
+
the same call.
|
|
107
|
+
|
|
108
|
+
## Installing
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
pip install planetmodel # numpy and scipy only
|
|
112
|
+
pip install 'planetmodel[meshing]' # 2D and 3D meshes via gmsh
|
|
113
|
+
pip install 'planetmodel[mfem]' # export to MFEM (PyMFEM)
|
|
114
|
+
pip install 'planetmodel[harmonics]' # grid transforms via pyshtools and ducc0
|
|
115
|
+
pip install 'planetmodel[plot]' # matplotlib, for the figures
|
|
116
|
+
pip install 'planetmodel[notebook]' # ipykernel, to run tutorials cell by cell
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Python 3.12 or later. Nothing optional is imported by `import
|
|
120
|
+
planetmodel`.
|
|
121
|
+
|
|
122
|
+
## Twelve lines
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
import numpy as np
|
|
126
|
+
from planetmodel import PREM, RadialMesh, flattening, gravity
|
|
127
|
+
|
|
128
|
+
m = PREM() # exact polynomials, SI
|
|
129
|
+
oc, mantle = m.layer("outer_core"), m.layer("lowermost_mantle")
|
|
130
|
+
cmb = m.geometry.interface("cmb").radius
|
|
131
|
+
print(oc["rho"](cmb), mantle["rho"](cmb), m.is_fluid("outer_core")) # both sides
|
|
132
|
+
print(m.elastic_moduli("lowermost_mantle")(cmb, 0.3, 0.0)[:3, :3] / 1e9) # Voigt, GPa
|
|
133
|
+
print(gravity(m, [cmb, 6371e3]), m.moduli_at("lower_mantle", 2 * np.pi / 3600)["L"](5e6))
|
|
134
|
+
|
|
135
|
+
nd = m.nondimensionalised().stretched(flattening(1 / 300, rmax=1.0))
|
|
136
|
+
mesh = RadialMesh(nd, ngll=5, drmax=0.05)
|
|
137
|
+
print(nd.G, mesh.nodal(nd, "rho").shape, nd.geometry.validity())
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Where to go next
|
|
141
|
+
|
|
142
|
+
- `examples/tutorials/`: twelve walkthroughs, from a skeleton to Love
|
|
143
|
+
numbers, random fields and deck files, each a `# %%` script that runs
|
|
144
|
+
headless.
|
|
145
|
+
- `src/planetmodel/mesh3d/manifest.py`: the manifest beside every mesh,
|
|
146
|
+
its schema described from the consumer's side.
|
|
147
|
+
- `CONTRIBUTING.md`: the development setup, the hooks, the test
|
|
148
|
+
selections and how a release is made.
|
|
149
|
+
|
|
150
|
+
## Tests
|
|
151
|
+
|
|
152
|
+
```
|
|
153
|
+
poetry run pytest # the fast suite
|
|
154
|
+
poetry run pytest -m "not slow" # with gmsh and MFEM
|
|
155
|
+
poetry run ruff check .
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Licence
|
|
159
|
+
|
|
160
|
+
BSD-3
|
|
161
|
+
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# planetmodel
|
|
2
|
+
|
|
3
|
+
Spherically layered planetary models: a skeleton of boundary radii, a
|
|
4
|
+
geometry that places it in the physical world through one continuous
|
|
5
|
+
mapping, fields on each layer, and the meshes that hand a model to a
|
|
6
|
+
solver.
|
|
7
|
+
|
|
8
|
+
The library covers the skeleton, the geometry and its mappings; fields
|
|
9
|
+
on one interval with an exact polynomial algebra; the model with its
|
|
10
|
+
units, named model types (PREM from its polynomials, simple layered
|
|
11
|
+
models, any mineos deck) and the mixins that complete them with moduli,
|
|
12
|
+
velocities, gravity and linear rheologies; a radial spectral-element
|
|
13
|
+
mesh; 2D and 3D meshes via gmsh with a manifest and export to MFEM; and
|
|
14
|
+
two sub-packages that consume the radial mesh: `planetmodel.loading`
|
|
15
|
+
solves the loading and tidal problem and gives Love numbers, and
|
|
16
|
+
`planetmodel.randomfield` draws Matern random fields on balls, annuli
|
|
17
|
+
and layers. A netCDF file for 3D models is next.
|
|
18
|
+
|
|
19
|
+
## The ideas
|
|
20
|
+
|
|
21
|
+
**A skeleton.** A strictly increasing list of boundary radii, possibly
|
|
22
|
+
starting above zero for a shell. It answers geometric questions
|
|
23
|
+
(intervals, where a radius lies, with the two sides of a boundary left to
|
|
24
|
+
the caller) and supports surgery: refine, truncate, hollow, extend,
|
|
25
|
+
coarsen.
|
|
26
|
+
|
|
27
|
+
**A geometry.** A skeleton, one mapping from the reference ball to the
|
|
28
|
+
physical body, and the names of layers and interfaces. The mapping must
|
|
29
|
+
be orientation-preserving, continuous, and kinked only on skeleton
|
|
30
|
+
boundaries; a geometry checks those invariants when it is built. The
|
|
31
|
+
shipped mapping is the radial stretch `m(X) = (r + h) e_r` driven by any
|
|
32
|
+
callable `h(r, theta, phi)`, with closed forms for its deformation
|
|
33
|
+
gradient, Jacobian, validity, inverse and linearisation; any object with
|
|
34
|
+
`__call__`, `deformation_gradient` and `jacobian` is a mapping.
|
|
35
|
+
|
|
36
|
+
**A field on one interval.** Data on one layer: an interval, a character
|
|
37
|
+
(the tensor rank and weight that say how it transforms), a name, and
|
|
38
|
+
`evaluate(r, theta, phi, *, frame)` giving components in the local
|
|
39
|
+
spherical frame or in Cartesian ones. A discontinuity is two layers
|
|
40
|
+
asked separately. Radial fields sit on layer functions whose algebra is
|
|
41
|
+
exact on polynomials, so PREM's moduli `rho v^2` are exact polynomials;
|
|
42
|
+
analytic formulas, pointwise compositions, and fields pushed forward
|
|
43
|
+
through a mapping are fields too. A field may be complex-valued, which
|
|
44
|
+
is what a model frozen at a frequency holds.
|
|
45
|
+
|
|
46
|
+
**One model class.** A geometry with a bag of fields on every layer.
|
|
47
|
+
What a name means comes from the shipped vocabulary or the specs a model
|
|
48
|
+
is given. A model type (`PREM`, `LayeredIsotropicElastic`, `MineosModel`,
|
|
49
|
+
or your own) is a class derived from `Model` alone; the mixins of
|
|
50
|
+
`planetmodel.behaviours` add the shared derivations as methods, written
|
|
51
|
+
once as free functions: the Love moduli beside the velocities, the
|
|
52
|
+
elastic tensor and its Voigt average, gravity, and the constant-Q and
|
|
53
|
+
Maxwell rheologies frozen at a frequency.
|
|
54
|
+
|
|
55
|
+
**Units in one place.** The model's `Scales` say what one stored unit
|
|
56
|
+
is in SI, and `converted` re-expresses the whole model by name, exactly
|
|
57
|
+
for polynomials; `G` is read in the model's units. Nothing else names a
|
|
58
|
+
unit: radii are numbers, every tolerance is relative, and the meshers
|
|
59
|
+
hand the geometry's numbers to gmsh unchanged.
|
|
60
|
+
|
|
61
|
+
**Two meshers.** `planetmodel.mesh1d` lays Gauss-Lobatto-Legendre
|
|
62
|
+
elements along the radius with every skeleton boundary an element
|
|
63
|
+
boundary, evaluates a model's fields and gravity on its nodes, and
|
|
64
|
+
samples a model on an angular grid. `planetmodel.mesh3d` meshes a
|
|
65
|
+
geometry, full or hollow, in 2D or 3D, with shells outside it, writes a
|
|
66
|
+
JSON manifest saying what every attribute means, and exports the mesh,
|
|
67
|
+
the mapping's displacement and the model's fields to MFEM.
|
|
68
|
+
|
|
69
|
+
**Executable contracts.** `planetmodel.testing` holds one `check_*`
|
|
70
|
+
function per protocol; the shipped implementations and yours are held to
|
|
71
|
+
the same call.
|
|
72
|
+
|
|
73
|
+
## Installing
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
pip install planetmodel # numpy and scipy only
|
|
77
|
+
pip install 'planetmodel[meshing]' # 2D and 3D meshes via gmsh
|
|
78
|
+
pip install 'planetmodel[mfem]' # export to MFEM (PyMFEM)
|
|
79
|
+
pip install 'planetmodel[harmonics]' # grid transforms via pyshtools and ducc0
|
|
80
|
+
pip install 'planetmodel[plot]' # matplotlib, for the figures
|
|
81
|
+
pip install 'planetmodel[notebook]' # ipykernel, to run tutorials cell by cell
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Python 3.12 or later. Nothing optional is imported by `import
|
|
85
|
+
planetmodel`.
|
|
86
|
+
|
|
87
|
+
## Twelve lines
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import numpy as np
|
|
91
|
+
from planetmodel import PREM, RadialMesh, flattening, gravity
|
|
92
|
+
|
|
93
|
+
m = PREM() # exact polynomials, SI
|
|
94
|
+
oc, mantle = m.layer("outer_core"), m.layer("lowermost_mantle")
|
|
95
|
+
cmb = m.geometry.interface("cmb").radius
|
|
96
|
+
print(oc["rho"](cmb), mantle["rho"](cmb), m.is_fluid("outer_core")) # both sides
|
|
97
|
+
print(m.elastic_moduli("lowermost_mantle")(cmb, 0.3, 0.0)[:3, :3] / 1e9) # Voigt, GPa
|
|
98
|
+
print(gravity(m, [cmb, 6371e3]), m.moduli_at("lower_mantle", 2 * np.pi / 3600)["L"](5e6))
|
|
99
|
+
|
|
100
|
+
nd = m.nondimensionalised().stretched(flattening(1 / 300, rmax=1.0))
|
|
101
|
+
mesh = RadialMesh(nd, ngll=5, drmax=0.05)
|
|
102
|
+
print(nd.G, mesh.nodal(nd, "rho").shape, nd.geometry.validity())
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Where to go next
|
|
106
|
+
|
|
107
|
+
- `examples/tutorials/`: twelve walkthroughs, from a skeleton to Love
|
|
108
|
+
numbers, random fields and deck files, each a `# %%` script that runs
|
|
109
|
+
headless.
|
|
110
|
+
- `src/planetmodel/mesh3d/manifest.py`: the manifest beside every mesh,
|
|
111
|
+
its schema described from the consumer's side.
|
|
112
|
+
- `CONTRIBUTING.md`: the development setup, the hooks, the test
|
|
113
|
+
selections and how a release is made.
|
|
114
|
+
|
|
115
|
+
## Tests
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
poetry run pytest # the fast suite
|
|
119
|
+
poetry run pytest -m "not slow" # with gmsh and MFEM
|
|
120
|
+
poetry run ruff check .
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Licence
|
|
124
|
+
|
|
125
|
+
BSD-3
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "planetmodel"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Spherically layered planetary models: reference bodies, fields, mappings and meshes"
|
|
5
|
+
keywords = ["geophysics", "seismology", "planetary models", "PREM", "spectral elements", "meshing"]
|
|
6
|
+
classifiers = [
|
|
7
|
+
"Development Status :: 3 - Alpha",
|
|
8
|
+
"Intended Audience :: Science/Research",
|
|
9
|
+
"Programming Language :: Python :: 3",
|
|
10
|
+
"Programming Language :: Python :: 3.12",
|
|
11
|
+
"Programming Language :: Python :: 3.13",
|
|
12
|
+
"Topic :: Scientific/Engineering :: Physics",
|
|
13
|
+
]
|
|
14
|
+
authors = [
|
|
15
|
+
{name = "David Al-Attar",email = "da380@cam.ac.uk"}
|
|
16
|
+
]
|
|
17
|
+
readme = "README.md"
|
|
18
|
+
license = "BSD-3-Clause"
|
|
19
|
+
license-files = ["LICENSE"]
|
|
20
|
+
requires-python = ">=3.12"
|
|
21
|
+
dependencies = [
|
|
22
|
+
"numpy>=2.5,<3",
|
|
23
|
+
"scipy>=1.18,<2",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
[project.urls]
|
|
27
|
+
Homepage = "https://github.com/da380/planetmodel"
|
|
28
|
+
Repository = "https://github.com/da380/planetmodel"
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
meshing = ["gmsh>=4.13"]
|
|
32
|
+
mfem = ["mfem>=4.8"]
|
|
33
|
+
netcdf = ["netCDF4>=1.7"]
|
|
34
|
+
plot = ["matplotlib>=3.11,<4"]
|
|
35
|
+
notebook = ["ipykernel>=6.29"]
|
|
36
|
+
harmonics = ["pyshtools (>=4.14)", "ducc0 (>=0.41)"]
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"pytest>=9",
|
|
41
|
+
"ruff>=0.6",
|
|
42
|
+
"pre-commit (>=4)",
|
|
43
|
+
"pytest-cov (>=6)",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.poetry]
|
|
47
|
+
packages = [{include = "planetmodel", from = "src"}]
|
|
48
|
+
|
|
49
|
+
[build-system]
|
|
50
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
51
|
+
build-backend = "poetry.core.masonry.api"
|
|
52
|
+
|
|
53
|
+
[tool.pytest.ini_options]
|
|
54
|
+
testpaths = ["tests"]
|
|
55
|
+
pythonpath = ["src"]
|
|
56
|
+
norecursedirs = ["archive", ".*", "build", "dist"]
|
|
57
|
+
# The fast suite is the default: it needs numpy and scipy alone, and the
|
|
58
|
+
# `plot` and `harmonics` extras where installed. `-m "not slow"` adds the
|
|
59
|
+
# gmsh unit geometries and the MFEM exports, `-m ""` everything.
|
|
60
|
+
addopts = "-m 'not gmsh and not mfem and not slow'"
|
|
61
|
+
markers = [
|
|
62
|
+
"slow: long-running tests (minutes); deselect with -m 'not slow'",
|
|
63
|
+
"gmsh: requires the optional gmsh dependency (planetmodel[meshing])",
|
|
64
|
+
"mfem: requires PyMFEM (planetmodel[mfem])",
|
|
65
|
+
"harmonics: requires pyshtools (planetmodel[harmonics])",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
[tool.ruff]
|
|
69
|
+
line-length = 88
|
|
70
|
+
src = ["src", "tests"]
|
|
71
|
+
extend-exclude = ["archive"]
|
|
72
|
+
|
|
73
|
+
[tool.ruff.lint]
|
|
74
|
+
select = ["E", "F", "W"]
|
|
75
|
+
# Deliberate house style, not defects:
|
|
76
|
+
# E741 `l` is the spherical-harmonic degree and `I` an integral -- the
|
|
77
|
+
# standard symbols in this field, used consistently throughout.
|
|
78
|
+
# E702 paired assignments to symmetric matrix entries are written on one
|
|
79
|
+
# line so the symmetry is visible.
|
|
80
|
+
# E731 short lambdas bound to names read as the mathematical definitions
|
|
81
|
+
# they are (fitters, coefficient functions).
|
|
82
|
+
ignore = ["E741", "E702", "E731"]
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""planetmodel: spherically layered planetary models, and their meshes.
|
|
2
|
+
|
|
3
|
+
A model is a skeleton of boundary radii, a geometry that places the
|
|
4
|
+
skeleton in the physical world through one continuous mapping, and a
|
|
5
|
+
bag of fields on each layer. This package holds the skeleton and the
|
|
6
|
+
geometry, the mappings that place them, the fields and the model, the
|
|
7
|
+
catalogue of named models, and the meshers that hand a model to a
|
|
8
|
+
solver. Every internal is numbers: the model alone carries units.
|
|
9
|
+
|
|
10
|
+
Modules reached by name, one level down:
|
|
11
|
+
|
|
12
|
+
frames the local spherical frame, tensors moved between frames, Voigt
|
|
13
|
+
materials velocity and moduli conversions, the elastic field, what a
|
|
14
|
+
layer's fields imply (fluidity, moduli)
|
|
15
|
+
rheology what a layer's rheology fields imply, and a model frozen at
|
|
16
|
+
a frequency with complex moduli
|
|
17
|
+
units Dimensions, Scales and the dimension constants
|
|
18
|
+
vocabulary the shipped field names, their characters and dimensions
|
|
19
|
+
behaviours the free functions as methods: `layer_method` and the mixins
|
|
20
|
+
catalogue PREM, LayeredIsotropicElastic and MineosModel, model types
|
|
21
|
+
deck tabulated models: decks, their formats, fields by interpolation
|
|
22
|
+
sampling a model on a radial mesh times an angular grid
|
|
23
|
+
harmonics real spherical harmonics; grid transforms via pyshtools (optional)
|
|
24
|
+
plotting radial profiles drawn one way, radius upward (matplotlib, optional)
|
|
25
|
+
mesh1d radial spectral-element meshes (GLL), nodal values, gravity
|
|
26
|
+
mesh3d 2D and 3D meshes via gmsh, and MFEM export
|
|
27
|
+
loading the loading and tidal problem on a radial mesh: Love numbers
|
|
28
|
+
randomfield Matern random fields on balls, annuli and layers
|
|
29
|
+
testing the executable contracts, `check_field` and its kin
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from .behaviours import (
|
|
33
|
+
ConstantQ,
|
|
34
|
+
Elastic,
|
|
35
|
+
SelfGravitating,
|
|
36
|
+
Viscoelastic,
|
|
37
|
+
layer_method,
|
|
38
|
+
with_moduli,
|
|
39
|
+
with_velocities,
|
|
40
|
+
)
|
|
41
|
+
from .catalogue import PREM, LayeredIsotropicElastic, MineosModel
|
|
42
|
+
from .character import DENSITY, ELASTIC, SCALAR, STRESS, VECTOR, Character, Symmetry
|
|
43
|
+
from .deck import (
|
|
44
|
+
MINEOS,
|
|
45
|
+
Deck,
|
|
46
|
+
DeckFormat,
|
|
47
|
+
Tabulated,
|
|
48
|
+
deck_layers,
|
|
49
|
+
read_deck,
|
|
50
|
+
write_deck,
|
|
51
|
+
)
|
|
52
|
+
from .displacement import (
|
|
53
|
+
CallableDisplacement,
|
|
54
|
+
RadialDisplacement,
|
|
55
|
+
ZeroDisplacement,
|
|
56
|
+
as_displacement,
|
|
57
|
+
flattening,
|
|
58
|
+
layer_linear,
|
|
59
|
+
)
|
|
60
|
+
from .fields import (
|
|
61
|
+
AnalyticField,
|
|
62
|
+
ComposedField,
|
|
63
|
+
Field,
|
|
64
|
+
FieldBase,
|
|
65
|
+
RadialField,
|
|
66
|
+
constant_field,
|
|
67
|
+
)
|
|
68
|
+
from .geometry import Geometry, InterfaceInfo, LayerInfo
|
|
69
|
+
from .harmonics import analyse_grid, real_harmonics, synthesise, synthesise_grid
|
|
70
|
+
from .layerfunction import (
|
|
71
|
+
LayerFunction,
|
|
72
|
+
NumericLayer,
|
|
73
|
+
PolynomialLayer,
|
|
74
|
+
as_layer_function,
|
|
75
|
+
constant_layer,
|
|
76
|
+
polynomial_fit,
|
|
77
|
+
polynomial_layer,
|
|
78
|
+
)
|
|
79
|
+
from .mapping import (
|
|
80
|
+
IdentityMapping,
|
|
81
|
+
Mapping,
|
|
82
|
+
MappingBase,
|
|
83
|
+
MappingPerturbation,
|
|
84
|
+
RadialStretch,
|
|
85
|
+
ScaledMapping,
|
|
86
|
+
ValidityReport,
|
|
87
|
+
outer_radius_of,
|
|
88
|
+
validity_lattice,
|
|
89
|
+
)
|
|
90
|
+
from .materials import ElasticField, elastic_moduli, is_fluid, kappa_mu, moduli
|
|
91
|
+
from .mesh1d import RadialMesh
|
|
92
|
+
from .mesh1d.gravity import gravity, gravity_fields, mass
|
|
93
|
+
from .model import Layer, Model
|
|
94
|
+
from .pushforward import PulledBackField, PushedForwardField, pull_back, push_forward
|
|
95
|
+
from .rheology import (
|
|
96
|
+
dispersive_moduli,
|
|
97
|
+
frozen,
|
|
98
|
+
frozen_moduli,
|
|
99
|
+
is_viscoelastic,
|
|
100
|
+
reference_omega,
|
|
101
|
+
)
|
|
102
|
+
from .sampling import AngularGrid, Sample, equiangular, gauss_legendre, sample
|
|
103
|
+
from .skeleton import CoarseningMap, Location, Skeleton
|
|
104
|
+
from .units import EARTH_MEAN_DENSITY, G_SI, Dimensions, Scales
|
|
105
|
+
from .vocabulary import CONSTANTS, VOCABULARY, Constant, FieldSpec
|
|
106
|
+
from . import testing # noqa: F401
|
|
107
|
+
|
|
108
|
+
__version__ = "1.0.0"
|
|
109
|
+
|
|
110
|
+
__all__ = [
|
|
111
|
+
"Skeleton",
|
|
112
|
+
"Location",
|
|
113
|
+
"CoarseningMap",
|
|
114
|
+
"Geometry",
|
|
115
|
+
"LayerInfo",
|
|
116
|
+
"InterfaceInfo",
|
|
117
|
+
"Mapping",
|
|
118
|
+
"MappingBase",
|
|
119
|
+
"IdentityMapping",
|
|
120
|
+
"RadialStretch",
|
|
121
|
+
"ScaledMapping",
|
|
122
|
+
"ValidityReport",
|
|
123
|
+
"MappingPerturbation",
|
|
124
|
+
"validity_lattice",
|
|
125
|
+
"outer_radius_of",
|
|
126
|
+
"RadialDisplacement",
|
|
127
|
+
"ZeroDisplacement",
|
|
128
|
+
"CallableDisplacement",
|
|
129
|
+
"as_displacement",
|
|
130
|
+
"RadialMesh",
|
|
131
|
+
"Character",
|
|
132
|
+
"SCALAR",
|
|
133
|
+
"DENSITY",
|
|
134
|
+
"VECTOR",
|
|
135
|
+
"STRESS",
|
|
136
|
+
"ELASTIC",
|
|
137
|
+
"Symmetry",
|
|
138
|
+
"LayerFunction",
|
|
139
|
+
"PolynomialLayer",
|
|
140
|
+
"NumericLayer",
|
|
141
|
+
"as_layer_function",
|
|
142
|
+
"polynomial_layer",
|
|
143
|
+
"constant_layer",
|
|
144
|
+
"polynomial_fit",
|
|
145
|
+
"Field",
|
|
146
|
+
"FieldBase",
|
|
147
|
+
"RadialField",
|
|
148
|
+
"AnalyticField",
|
|
149
|
+
"ComposedField",
|
|
150
|
+
"constant_field",
|
|
151
|
+
"ElasticField",
|
|
152
|
+
"is_fluid",
|
|
153
|
+
"moduli",
|
|
154
|
+
"elastic_moduli",
|
|
155
|
+
"kappa_mu",
|
|
156
|
+
"is_viscoelastic",
|
|
157
|
+
"frozen_moduli",
|
|
158
|
+
"dispersive_moduli",
|
|
159
|
+
"frozen",
|
|
160
|
+
"reference_omega",
|
|
161
|
+
"push_forward",
|
|
162
|
+
"pull_back",
|
|
163
|
+
"PushedForwardField",
|
|
164
|
+
"PulledBackField",
|
|
165
|
+
"Dimensions",
|
|
166
|
+
"Scales",
|
|
167
|
+
"G_SI",
|
|
168
|
+
"EARTH_MEAN_DENSITY",
|
|
169
|
+
"FieldSpec",
|
|
170
|
+
"Constant",
|
|
171
|
+
"VOCABULARY",
|
|
172
|
+
"CONSTANTS",
|
|
173
|
+
"Layer",
|
|
174
|
+
"Model",
|
|
175
|
+
"layer_method",
|
|
176
|
+
"with_moduli",
|
|
177
|
+
"with_velocities",
|
|
178
|
+
"Elastic",
|
|
179
|
+
"ConstantQ",
|
|
180
|
+
"SelfGravitating",
|
|
181
|
+
"Viscoelastic",
|
|
182
|
+
"PREM",
|
|
183
|
+
"LayeredIsotropicElastic",
|
|
184
|
+
"MineosModel",
|
|
185
|
+
"Deck",
|
|
186
|
+
"DeckFormat",
|
|
187
|
+
"MINEOS",
|
|
188
|
+
"read_deck",
|
|
189
|
+
"write_deck",
|
|
190
|
+
"deck_layers",
|
|
191
|
+
"Tabulated",
|
|
192
|
+
"flattening",
|
|
193
|
+
"layer_linear",
|
|
194
|
+
"AngularGrid",
|
|
195
|
+
"Sample",
|
|
196
|
+
"sample",
|
|
197
|
+
"gauss_legendre",
|
|
198
|
+
"equiangular",
|
|
199
|
+
"real_harmonics",
|
|
200
|
+
"synthesise",
|
|
201
|
+
"synthesise_grid",
|
|
202
|
+
"analyse_grid",
|
|
203
|
+
"gravity",
|
|
204
|
+
"mass",
|
|
205
|
+
"gravity_fields",
|
|
206
|
+
"testing",
|
|
207
|
+
"__version__",
|
|
208
|
+
]
|