taurex-pcq 1.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.
- taurex_pcq-1.0/LICENSE +29 -0
- taurex_pcq-1.0/PKG-INFO +99 -0
- taurex_pcq-1.0/README.md +72 -0
- taurex_pcq-1.0/pyproject.toml +47 -0
- taurex_pcq-1.0/setup.cfg +4 -0
- taurex_pcq-1.0/src/taurex_pcq/__init__.py +3 -0
- taurex_pcq-1.0/src/taurex_pcq/contributions/__init__.py +1 -0
- taurex_pcq-1.0/src/taurex_pcq/contributions/pymiescatt_grid.py +393 -0
- taurex_pcq-1.0/src/taurex_pcq.egg-info/PKG-INFO +99 -0
- taurex_pcq-1.0/src/taurex_pcq.egg-info/SOURCES.txt +12 -0
- taurex_pcq-1.0/src/taurex_pcq.egg-info/dependency_links.txt +1 -0
- taurex_pcq-1.0/src/taurex_pcq.egg-info/entry_points.txt +2 -0
- taurex_pcq-1.0/src/taurex_pcq.egg-info/requires.txt +10 -0
- taurex_pcq-1.0/src/taurex_pcq.egg-info/top_level.txt +1 -0
taurex_pcq-1.0/LICENSE
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Mael Voyer
|
|
4
|
+
All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
10
|
+
list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
13
|
+
this list of conditions and the following disclaimer in the documentation
|
|
14
|
+
and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
21
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
22
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
23
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
24
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
25
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
26
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
27
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
28
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
29
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
taurex_pcq-1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: taurex-pcq
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: A TauREx plugin implementing Pre Computed Qext grids for cloud models
|
|
5
|
+
Author-email: Maël Voyer <mael.voyer@cea.fr>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: taurex,exoplanets,retrieval,atmospheres,jwst
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: numpy
|
|
18
|
+
Requires-Dist: taurex
|
|
19
|
+
Requires-Dist: numba
|
|
20
|
+
Requires-Dist: scipy
|
|
21
|
+
Requires-Dist: h5py
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build; extra == "dev"
|
|
24
|
+
Requires-Dist: twine; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# Faster clouds for TauREx 3
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
This plugin provides **a new nethod to inclue aerosols** in [TauREx 3](https://github.com/ucl-exoplanets/TauREx3_public), extending the TauREx-PyMieScatt plugin. It significantly speeds up the cloud models by using precomputed extinction efficiency (`Q_ext`) grids. TauREx-PCQ also considerably improves the computation scaling with the number of clouds in the models. The speed-ups for single cloud retrievals are betwwen 1.4 and 2.7. Although, a single-cloud retrieval using Qext grids achieved a speed-up of 1.4, the same retrieval with four clouds became 17 times faster than the corresponding retrieval using direct Mie calculations.
|
|
32
|
+
The grids details and validation can be found in Voyer & Changeat (2026), if you use TauREx-PCQ or the grids please cite this paper. The species already available are Mg2SiO4, MgSiO3 (amorph sol-gel and amorph glass), SiO2 (alpha and amorph), SiO, the Titan tholins and water ice. They can be found at: [10.5281/zenodo.17456673](https://doi.org/10.5281/zenodo.17456673) .
|
|
33
|
+
|
|
34
|
+
For any inquiries, please contact: mael.voyer@u-paris.fr
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 🔧 Features
|
|
39
|
+
|
|
40
|
+
- ✅ Compatible with `transit` and `emmsion` models.
|
|
41
|
+
- ✅ Works with any aerosol specie given that the user provides a `.h5` file with :
|
|
42
|
+
|
|
43
|
+
- A `radius_grid` dataset with the particule sizes in microns ( length `a` ).
|
|
44
|
+
- A `wavenumber_grid` dataset with the wavenumber at which the `Q_ext` were computed in cm-1 ( length `b` )
|
|
45
|
+
- A `Qext_grid` dataset with the computed `Q_ext` from PyMieScat ( length (`a`, `b`) )
|
|
46
|
+
|
|
47
|
+
## As an extension of TauREx-PyMieScatt, this pulgin includes the same capabilities
|
|
48
|
+
|
|
49
|
+
- ✅ **Supports multiple particle size distributions:**
|
|
50
|
+
- `normal` (log-normal)
|
|
51
|
+
- `budaj` (2015)
|
|
52
|
+
- `deirmendjian` (1964)
|
|
53
|
+
- ✅ **Multiple species and per-species fitting**
|
|
54
|
+
- ✅ **Particle decay with altitude** (`exp_decay` based on Whitten 2008 / Atreya 2005)
|
|
55
|
+
- ✅ **Computes exctinction** using the species optical constant via **Effective Medium Theory (Bohren & Huffman 1983)**
|
|
56
|
+
- ✅ **Multiple fittable parameters** for TauREx retrievals
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 🔧 Model Parameters
|
|
61
|
+
|
|
62
|
+
| Name | Description |
|
|
63
|
+
|------|-------------|
|
|
64
|
+
| `species` | Your name for the species included through the `mie_species_path` parameter. This name will be used as suffixes added to the other parameters to distinguish between included species. |
|
|
65
|
+
| `mie_species_path` | Paths to the `Q_ext` grids of the aerosols you want to include |
|
|
66
|
+
| `mie_particle_radius_distribution` | `"normal"`, `"budaj"`, or `"deirmendjian"` |
|
|
67
|
+
| `mie_particle_mean_radius` | Mean particle radius (µm) |
|
|
68
|
+
| `mie_particle_logstd_radius` | Log-normal std dev (for `"normal"` distribution) |
|
|
69
|
+
| `mie_particle_paramA/B/C/D` | Parameters for Deirmendjian distribution |
|
|
70
|
+
| `mie_particle_mix_ratio` | Number density (molecules/m³) |
|
|
71
|
+
| `mie_midP` | Pressure at cloud center (Pa) |
|
|
72
|
+
| `mie_rangeP` | Extend of the clouds in log scale around `mie_midP`. If `mie_midP` = 1e5 Pa and `mie_rangeP` = 1 then clouds extend from 1e6 to 1e4 Pa |
|
|
73
|
+
| `mie_particle_altitude_distrib` | Currently supports `'exp_decay'` or `'linear'` |
|
|
74
|
+
| `mie_particle_altitude_decay` | Decay exponent per species e.g `-5` |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 💡 Usage Example in a TauREx parameter file or 'parfile'
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
[Model]
|
|
82
|
+
model_type = transit
|
|
83
|
+
|
|
84
|
+
[[PyMieScattGridExtinction]]
|
|
85
|
+
|
|
86
|
+
species = SiO, Mg2SiO4_glass, custom_molecule
|
|
87
|
+
mie_species_path = path_to_SiO.h5 , path_to_Mg2SiO4_glass.h5 , path_to_custom_molecule.h5 #e.g. You can use the optical constant from Kitzmann and Heng 2018
|
|
88
|
+
mie_particle_radius_distribution = budaj
|
|
89
|
+
mie_particle_mean_radius = 0.1, 0.4 , 10
|
|
90
|
+
mie_midP = 1e5, 1e2, 1
|
|
91
|
+
mie_rangeP = 3 , 1 , 2
|
|
92
|
+
mie_particle_mix_ratio = 1e5, 1e8 , 10e3
|
|
93
|
+
mie_particle_radius_Nsampling = 5
|
|
94
|
+
mie_particle_altitude_distrib = linear
|
|
95
|
+
```
|
|
96
|
+
---
|
|
97
|
+
## Limitations
|
|
98
|
+
|
|
99
|
+
As the `Q_ext` are computed for a range of radii between 1 nm and 30 microns, it is strongly recomended that the `mie_particle_mean_radius` prior does not extend beyond this range. Any radius outside of the range will use the `Q_ext` of the closest radius present in the grid.
|
taurex_pcq-1.0/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Faster clouds for TauREx 3
|
|
2
|
+
---
|
|
3
|
+
|
|
4
|
+
This plugin provides **a new nethod to inclue aerosols** in [TauREx 3](https://github.com/ucl-exoplanets/TauREx3_public), extending the TauREx-PyMieScatt plugin. It significantly speeds up the cloud models by using precomputed extinction efficiency (`Q_ext`) grids. TauREx-PCQ also considerably improves the computation scaling with the number of clouds in the models. The speed-ups for single cloud retrievals are betwwen 1.4 and 2.7. Although, a single-cloud retrieval using Qext grids achieved a speed-up of 1.4, the same retrieval with four clouds became 17 times faster than the corresponding retrieval using direct Mie calculations.
|
|
5
|
+
The grids details and validation can be found in Voyer & Changeat (2026), if you use TauREx-PCQ or the grids please cite this paper. The species already available are Mg2SiO4, MgSiO3 (amorph sol-gel and amorph glass), SiO2 (alpha and amorph), SiO, the Titan tholins and water ice. They can be found at: [10.5281/zenodo.17456673](https://doi.org/10.5281/zenodo.17456673) .
|
|
6
|
+
|
|
7
|
+
For any inquiries, please contact: mael.voyer@u-paris.fr
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 🔧 Features
|
|
12
|
+
|
|
13
|
+
- ✅ Compatible with `transit` and `emmsion` models.
|
|
14
|
+
- ✅ Works with any aerosol specie given that the user provides a `.h5` file with :
|
|
15
|
+
|
|
16
|
+
- A `radius_grid` dataset with the particule sizes in microns ( length `a` ).
|
|
17
|
+
- A `wavenumber_grid` dataset with the wavenumber at which the `Q_ext` were computed in cm-1 ( length `b` )
|
|
18
|
+
- A `Qext_grid` dataset with the computed `Q_ext` from PyMieScat ( length (`a`, `b`) )
|
|
19
|
+
|
|
20
|
+
## As an extension of TauREx-PyMieScatt, this pulgin includes the same capabilities
|
|
21
|
+
|
|
22
|
+
- ✅ **Supports multiple particle size distributions:**
|
|
23
|
+
- `normal` (log-normal)
|
|
24
|
+
- `budaj` (2015)
|
|
25
|
+
- `deirmendjian` (1964)
|
|
26
|
+
- ✅ **Multiple species and per-species fitting**
|
|
27
|
+
- ✅ **Particle decay with altitude** (`exp_decay` based on Whitten 2008 / Atreya 2005)
|
|
28
|
+
- ✅ **Computes exctinction** using the species optical constant via **Effective Medium Theory (Bohren & Huffman 1983)**
|
|
29
|
+
- ✅ **Multiple fittable parameters** for TauREx retrievals
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 🔧 Model Parameters
|
|
34
|
+
|
|
35
|
+
| Name | Description |
|
|
36
|
+
|------|-------------|
|
|
37
|
+
| `species` | Your name for the species included through the `mie_species_path` parameter. This name will be used as suffixes added to the other parameters to distinguish between included species. |
|
|
38
|
+
| `mie_species_path` | Paths to the `Q_ext` grids of the aerosols you want to include |
|
|
39
|
+
| `mie_particle_radius_distribution` | `"normal"`, `"budaj"`, or `"deirmendjian"` |
|
|
40
|
+
| `mie_particle_mean_radius` | Mean particle radius (µm) |
|
|
41
|
+
| `mie_particle_logstd_radius` | Log-normal std dev (for `"normal"` distribution) |
|
|
42
|
+
| `mie_particle_paramA/B/C/D` | Parameters for Deirmendjian distribution |
|
|
43
|
+
| `mie_particle_mix_ratio` | Number density (molecules/m³) |
|
|
44
|
+
| `mie_midP` | Pressure at cloud center (Pa) |
|
|
45
|
+
| `mie_rangeP` | Extend of the clouds in log scale around `mie_midP`. If `mie_midP` = 1e5 Pa and `mie_rangeP` = 1 then clouds extend from 1e6 to 1e4 Pa |
|
|
46
|
+
| `mie_particle_altitude_distrib` | Currently supports `'exp_decay'` or `'linear'` |
|
|
47
|
+
| `mie_particle_altitude_decay` | Decay exponent per species e.g `-5` |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 💡 Usage Example in a TauREx parameter file or 'parfile'
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
[Model]
|
|
55
|
+
model_type = transit
|
|
56
|
+
|
|
57
|
+
[[PyMieScattGridExtinction]]
|
|
58
|
+
|
|
59
|
+
species = SiO, Mg2SiO4_glass, custom_molecule
|
|
60
|
+
mie_species_path = path_to_SiO.h5 , path_to_Mg2SiO4_glass.h5 , path_to_custom_molecule.h5 #e.g. You can use the optical constant from Kitzmann and Heng 2018
|
|
61
|
+
mie_particle_radius_distribution = budaj
|
|
62
|
+
mie_particle_mean_radius = 0.1, 0.4 , 10
|
|
63
|
+
mie_midP = 1e5, 1e2, 1
|
|
64
|
+
mie_rangeP = 3 , 1 , 2
|
|
65
|
+
mie_particle_mix_ratio = 1e5, 1e8 , 10e3
|
|
66
|
+
mie_particle_radius_Nsampling = 5
|
|
67
|
+
mie_particle_altitude_distrib = linear
|
|
68
|
+
```
|
|
69
|
+
---
|
|
70
|
+
## Limitations
|
|
71
|
+
|
|
72
|
+
As the `Q_ext` are computed for a range of radii between 1 nm and 30 microns, it is strongly recomended that the `mie_particle_mean_radius` prior does not extend beyond this range. Any radius outside of the range will use the `Q_ext` of the closest radius present in the grid.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "taurex-pcq"
|
|
7
|
+
version = "1.0"
|
|
8
|
+
description = "A TauREx plugin implementing Pre Computed Qext grids for cloud models"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Maël Voyer", email = "mael.voyer@cea.fr" }
|
|
14
|
+
]
|
|
15
|
+
keywords = ["taurex", "exoplanets", "retrieval", "atmospheres", "jwst"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Programming Language :: Python :: 3",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Operating System :: OS Independent",
|
|
21
|
+
"Intended Audience :: Science/Research",
|
|
22
|
+
"Topic :: Scientific/Engineering :: Astronomy",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
dependencies = [
|
|
26
|
+
"numpy",
|
|
27
|
+
"taurex",
|
|
28
|
+
"numba",
|
|
29
|
+
"scipy",
|
|
30
|
+
"h5py"
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
dev = [
|
|
35
|
+
"build",
|
|
36
|
+
"twine",
|
|
37
|
+
"pytest",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.entry-points."taurex.plugins"]
|
|
41
|
+
taurex-pcq = "taurex_pcq"
|
|
42
|
+
|
|
43
|
+
[tool.setuptools]
|
|
44
|
+
package-dir = {"" = "src"}
|
|
45
|
+
|
|
46
|
+
[tool.setuptools.packages.find]
|
|
47
|
+
where = ["src"]
|
taurex_pcq-1.0/setup.cfg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .pymiescatt_grid import PyMieScattGridExtinctionContribution
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
from taurex.contributions.contribution import Contribution
|
|
2
|
+
import numpy as np
|
|
3
|
+
from taurex.data.fittable import fitparam
|
|
4
|
+
import numba
|
|
5
|
+
import scipy.stats as stats
|
|
6
|
+
import h5py
|
|
7
|
+
from taurex.exceptions import InvalidModelException
|
|
8
|
+
from taurex.util.util import create_grid_res
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@numba.jit(nopython=True, nogil=True)
|
|
12
|
+
def contribute_mie_tau(startK, endK, sigma, path, ngrid, layer, tau):
|
|
13
|
+
for k in range(startK, endK):
|
|
14
|
+
_path = path[k]
|
|
15
|
+
for wn in range(ngrid):
|
|
16
|
+
tau[layer, wn] += sigma[k+layer, wn]*_path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class InvalidPyMieScattGridException(InvalidModelException):
|
|
20
|
+
"""
|
|
21
|
+
Exception that is called when the contributio fails
|
|
22
|
+
"""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
class PyMieScattGridExtinctionContribution(Contribution):
|
|
26
|
+
"""
|
|
27
|
+
Computes Mie scattering contribution to optical depth
|
|
28
|
+
using the Bohren and Huffmann in its PyMieScatt implementation.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
mie_particle_mean_radius: Mean radius of the particles in um
|
|
33
|
+
mie_particle_mix_ratio: Number density in molecules/m^3 --> Divide this number by 1,000,000 to get this in more common molecules/cm^3
|
|
34
|
+
mie_midP: Middle of the clouds in Pa
|
|
35
|
+
mie_rangeP: Extend of the clouds in log scale. If mie_midP = 1e5 Pa and mie_rangeP = 1 then clouds extend from 1e6 to 1e4 Pa
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, mie_particle_mean_radius=[0.01,],
|
|
39
|
+
mie_particle_logstd_radius = [0.001], ## Serves for the normaly distributed particle size distribution.
|
|
40
|
+
mie_particle_paramA = [1., ], mie_particle_paramB = [6.,], mie_particle_paramC = [6.,], mie_particle_paramD = [1.,], ## Serves for Deirmendjian particle size distribution.
|
|
41
|
+
mie_particle_radius_Nsampling = 5, mie_particle_radius_Dsampling = 2, ## Is used for sampling the particle distribution.
|
|
42
|
+
mie_particle_radius_distribution = 'normal', ## choices are 'normal', 'budaj', 'deirmendjian'.
|
|
43
|
+
mie_species_path=None, species = ['Mg2SiO4'],
|
|
44
|
+
mie_particle_mix_ratio=[1e-10],
|
|
45
|
+
mie_porosity = None,
|
|
46
|
+
mie_midP = [1e3],
|
|
47
|
+
mie_rangeP = [1],
|
|
48
|
+
mie_nMedium=1,
|
|
49
|
+
mie_resolution = 100,
|
|
50
|
+
mie_particle_altitude_distrib = 'exp_decay',
|
|
51
|
+
mie_particle_altitude_decay = [-5], ## Controls the decay rate, inspired by Whitten et al. 2008 / Attreya et al. 2005
|
|
52
|
+
name = 'PyMieScattGridExtinction'):
|
|
53
|
+
super().__init__(name)
|
|
54
|
+
|
|
55
|
+
self._mie_particle_mean_radius = mie_particle_mean_radius
|
|
56
|
+
self._mie_particle_std_radius = mie_particle_logstd_radius
|
|
57
|
+
self._mie_particle_paramA = mie_particle_paramA
|
|
58
|
+
self._mie_particle_paramB = mie_particle_paramB
|
|
59
|
+
self._mie_particle_paramC = mie_particle_paramC
|
|
60
|
+
self._mie_particle_paramD = mie_particle_paramD
|
|
61
|
+
|
|
62
|
+
if mie_particle_radius_distribution == 'deirmendjian':
|
|
63
|
+
self._mie_particle_mean_radius = None
|
|
64
|
+
self.warning('The Rmean parameter is being disabled because not needed for Deirmendjian 1964 particle distribution')
|
|
65
|
+
else:
|
|
66
|
+
self._mie_particle_paramA = None
|
|
67
|
+
self.warning('The mie_particle_paramA parameter is being disabled because only used in Deirmendjian 1964 particle distribution')
|
|
68
|
+
|
|
69
|
+
if mie_particle_radius_distribution == 'budaj':
|
|
70
|
+
self._mie_particle_std_radius = None
|
|
71
|
+
self.warning('The Rlogstd parameter is being disabled because not needed for Bujaj 2015 particle distribution')
|
|
72
|
+
|
|
73
|
+
self._mie_particle_radius_distribution = mie_particle_radius_distribution
|
|
74
|
+
|
|
75
|
+
self._mie_particle_mix_ratio = mie_particle_mix_ratio
|
|
76
|
+
self._mie_porosity = mie_porosity
|
|
77
|
+
|
|
78
|
+
self._mie_midP = mie_midP
|
|
79
|
+
self._mie_rangeP = mie_rangeP
|
|
80
|
+
|
|
81
|
+
self._Nsampling = int(mie_particle_radius_Nsampling)
|
|
82
|
+
self._Dsampling = mie_particle_radius_Dsampling
|
|
83
|
+
|
|
84
|
+
self._mie_species_path = mie_species_path
|
|
85
|
+
self._species = species
|
|
86
|
+
|
|
87
|
+
self._particle_alt_distib = mie_particle_altitude_distrib
|
|
88
|
+
self._particle_alt_decay = mie_particle_altitude_decay
|
|
89
|
+
self._mie_nMedium = mie_nMedium
|
|
90
|
+
|
|
91
|
+
self._resolution = mie_resolution
|
|
92
|
+
|
|
93
|
+
self._radius_grid, self._Qext, self._Qext_wn = self.load_input_files(self._mie_species_path)
|
|
94
|
+
|
|
95
|
+
self.generate_particle_fitting_params()
|
|
96
|
+
|
|
97
|
+
def load_input_files(self, paths : list[str] ):
|
|
98
|
+
radius_grids, Qexts, wavenumber_grids = [], [], []
|
|
99
|
+
|
|
100
|
+
for path in paths:
|
|
101
|
+
grid_file = h5py.File(path)
|
|
102
|
+
radius_grids.append( grid_file["radius_grid"][()] )
|
|
103
|
+
Qexts.append( grid_file["Qext"][()] )
|
|
104
|
+
wavenumber_grids.append( grid_file["wavenumber_grid"][()] )
|
|
105
|
+
grid_file.close()
|
|
106
|
+
|
|
107
|
+
return radius_grids, Qexts, wavenumber_grids
|
|
108
|
+
|
|
109
|
+
def contribute(self, model, start_layer, end_layer,
|
|
110
|
+
density_offset, layer, density, tau, path_length=None):
|
|
111
|
+
|
|
112
|
+
contribute_mie_tau(start_layer, end_layer, self.sigma_xsec, path_length, self._ngrid, layer, tau)
|
|
113
|
+
|
|
114
|
+
def generate_particle_fitting_params(self):
|
|
115
|
+
|
|
116
|
+
bounds_Rm = [0.01, 10]
|
|
117
|
+
bounds_Rstd = [0.01, 0.2]
|
|
118
|
+
bounds_X = [1e0, 1e12]
|
|
119
|
+
bounds_midP = [1e6, 1e0]
|
|
120
|
+
bounds_rangeP = [0.0, 3]
|
|
121
|
+
bounds_decayP = [-7, 0]
|
|
122
|
+
bounds_poro = [0,1]
|
|
123
|
+
|
|
124
|
+
### CREATE JOINED FITPARAMS
|
|
125
|
+
if self._mie_particle_mean_radius is not None:
|
|
126
|
+
param_name = 'Rmean_share'
|
|
127
|
+
param_latex = '$Rmean_share$'
|
|
128
|
+
def read_RmeanShare(self):
|
|
129
|
+
return np.mean(self._mie_particle_mean_radius)
|
|
130
|
+
def write_RmeanShare(self, value):
|
|
131
|
+
self._mie_particle_mean_radius[:] = [value]*len(self._mie_particle_mean_radius)
|
|
132
|
+
default_fit = False
|
|
133
|
+
self.add_fittable_param(param_name, param_latex, read_RmeanShare,
|
|
134
|
+
write_RmeanShare, 'log', default_fit, bounds_Rm)
|
|
135
|
+
if self._mie_particle_std_radius is not None:
|
|
136
|
+
param_name = 'Rlogstd_share'
|
|
137
|
+
param_latex = '$Rlogstd_share$'
|
|
138
|
+
def read_RstdShare(self):
|
|
139
|
+
return np.mean(self._mie_particle_std_radius)
|
|
140
|
+
def write_RstdShare(self, value):
|
|
141
|
+
self._mie_particle_std_radius[:] = [value]*len(self._mie_particle_std_radius)
|
|
142
|
+
default_fit = False
|
|
143
|
+
self.add_fittable_param(param_name, param_latex, read_RstdShare,
|
|
144
|
+
write_RstdShare, 'linear', default_fit, bounds_Rstd)
|
|
145
|
+
|
|
146
|
+
param_name = 'X_share'
|
|
147
|
+
param_latex = '$X_share$'
|
|
148
|
+
def read_XShare(self):
|
|
149
|
+
return np.mean(self._mie_particle_mix_ratio)
|
|
150
|
+
def write_XShare(self, value):
|
|
151
|
+
self._mie_particle_mix_ratio = [value]*len(self._mie_particle_mix_ratio)
|
|
152
|
+
default_fit = False
|
|
153
|
+
self.add_fittable_param(param_name, param_latex, read_XShare,
|
|
154
|
+
write_XShare, 'log', default_fit, bounds_X)
|
|
155
|
+
|
|
156
|
+
param_name = 'midP_share'
|
|
157
|
+
param_latex = '$midP_share$'
|
|
158
|
+
def read_midPShare(self):
|
|
159
|
+
return np.mean(self._mie_midP)
|
|
160
|
+
def write_midPShare(self, value):
|
|
161
|
+
self._mie_midP[:] = [value]*len(self._mie_midP)
|
|
162
|
+
default_fit = False
|
|
163
|
+
self.add_fittable_param(param_name, param_latex, read_midPShare,
|
|
164
|
+
write_midPShare, 'log', default_fit, bounds_midP)
|
|
165
|
+
|
|
166
|
+
param_name = 'rangeP_share'
|
|
167
|
+
param_latex = '$rangeP_share$'
|
|
168
|
+
def read_rangePShare(self):
|
|
169
|
+
return np.mean(self._mie_rangeP)
|
|
170
|
+
def write_rangePShare(self, value):
|
|
171
|
+
self._mie_rangeP[:] = [value]*len(self._mie_rangeP)
|
|
172
|
+
default_fit = False
|
|
173
|
+
self.add_fittable_param(param_name, param_latex, read_rangePShare,
|
|
174
|
+
write_rangePShare, 'linear', default_fit, bounds_rangeP)
|
|
175
|
+
|
|
176
|
+
param_name = 'decayP_share'
|
|
177
|
+
param_latex = '$decayP_share$'
|
|
178
|
+
def read_decayPShare(self):
|
|
179
|
+
return np.mean(self._particle_alt_decay)
|
|
180
|
+
def write_decayPShare(self, value):
|
|
181
|
+
self._particle_alt_decay[:] = [value]*len(self._particle_alt_decay)
|
|
182
|
+
default_fit = False
|
|
183
|
+
self.add_fittable_param(param_name, param_latex, read_decayPShare,
|
|
184
|
+
write_decayPShare, 'linear', default_fit, bounds_decayP)
|
|
185
|
+
|
|
186
|
+
### CREATE INDIVIDUAL SPECIES FITPARAMS
|
|
187
|
+
for idx, val in enumerate(self._species):
|
|
188
|
+
|
|
189
|
+
if self._mie_particle_mean_radius is not None:
|
|
190
|
+
param_name = 'Rmean_{}'.format(val)
|
|
191
|
+
param_latex = '$Rmean_{}$'.format(val)
|
|
192
|
+
def read_Rmean(self, idx=idx):
|
|
193
|
+
return self._mie_particle_mean_radius[idx]
|
|
194
|
+
def write_Rmean(self, value, idx=idx):
|
|
195
|
+
self._mie_particle_mean_radius[idx] = value
|
|
196
|
+
default_fit = False
|
|
197
|
+
self.add_fittable_param(param_name, param_latex, read_Rmean,
|
|
198
|
+
write_Rmean, 'log', default_fit, bounds_Rm)
|
|
199
|
+
|
|
200
|
+
if self._mie_particle_std_radius is not None:
|
|
201
|
+
param_name = 'Rlogstd_{}'.format(val)
|
|
202
|
+
param_latex = '$Rlogstd_{}$'.format(val)
|
|
203
|
+
def read_Rstd(self, idx=idx):
|
|
204
|
+
return self._mie_particle_std_radius[idx]
|
|
205
|
+
def write_Rstd(self, value, idx=idx):
|
|
206
|
+
self._mie_particle_std_radius[idx] = value
|
|
207
|
+
default_fit = False
|
|
208
|
+
self.add_fittable_param(param_name, param_latex, read_Rstd,
|
|
209
|
+
write_Rstd, 'linear', default_fit, bounds_Rstd)
|
|
210
|
+
|
|
211
|
+
if self._mie_porosity is not None:
|
|
212
|
+
param_name = 'Porosity_{}'.format(val)
|
|
213
|
+
param_latex = '$Porosity_{}$'.format(val)
|
|
214
|
+
def read_Poro(self, idx=idx):
|
|
215
|
+
return self._mie_porosity[idx]
|
|
216
|
+
def write_Poro(self, value, idx=idx):
|
|
217
|
+
self._mie_porosity[idx] = value
|
|
218
|
+
default_fit = False
|
|
219
|
+
self.add_fittable_param(param_name, param_latex, read_Poro,
|
|
220
|
+
write_Poro, 'linear', default_fit, bounds_poro)
|
|
221
|
+
|
|
222
|
+
param_name = 'X_{}'.format(val)
|
|
223
|
+
param_latex = '$X_{}$'.format(val)
|
|
224
|
+
def read_X(self, idx=idx):
|
|
225
|
+
return self._mie_particle_mix_ratio[idx]
|
|
226
|
+
def write_X(self, value, idx=idx):
|
|
227
|
+
self._mie_particle_mix_ratio[idx] = value
|
|
228
|
+
default_fit = False
|
|
229
|
+
self.add_fittable_param(param_name, param_latex, read_X,
|
|
230
|
+
write_X, 'log', default_fit, bounds_X)
|
|
231
|
+
|
|
232
|
+
param_name = 'midP_{}'.format(val)
|
|
233
|
+
param_latex = '$midP_{}$'.format(val)
|
|
234
|
+
def read_midP(self, idx=idx):
|
|
235
|
+
return self._mie_midP[idx]
|
|
236
|
+
def write_midP(self, value, idx=idx):
|
|
237
|
+
self._mie_midP[idx] = value
|
|
238
|
+
default_fit = False
|
|
239
|
+
self.add_fittable_param(param_name, param_latex, read_midP,
|
|
240
|
+
write_midP, 'log', default_fit, bounds_midP)
|
|
241
|
+
|
|
242
|
+
param_name = 'rangeP_{}'.format(val)
|
|
243
|
+
param_latex = '$rangeP_{}$'.format(val)
|
|
244
|
+
def read_rangeP(self, idx=idx):
|
|
245
|
+
return self._mie_rangeP[idx]
|
|
246
|
+
def write_rangeP(self, value, idx=idx):
|
|
247
|
+
self._mie_rangeP[idx] = value
|
|
248
|
+
default_fit = False
|
|
249
|
+
self.add_fittable_param(param_name, param_latex, read_rangeP,
|
|
250
|
+
write_rangeP, 'linear', default_fit, bounds_rangeP)
|
|
251
|
+
|
|
252
|
+
param_name = 'decayP_{}'.format(val)
|
|
253
|
+
param_latex = '$decayP_{}$'.format(val)
|
|
254
|
+
def read_decayP(self, idx=idx):
|
|
255
|
+
return self._particle_alt_decay[idx]
|
|
256
|
+
def write_decayP(self, value, idx=idx):
|
|
257
|
+
self._particle_alt_decay[idx] = value
|
|
258
|
+
default_fit = False
|
|
259
|
+
self.add_fittable_param(param_name, param_latex, read_decayP,
|
|
260
|
+
write_decayP, 'linear', default_fit, bounds_decayP)
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
def prepare_each(self, model, wngrid):
|
|
264
|
+
|
|
265
|
+
self._nlayers = model.nLayers
|
|
266
|
+
self._ngrid = wngrid.shape[0]
|
|
267
|
+
|
|
268
|
+
pressure_profile = model.pressureProfile
|
|
269
|
+
|
|
270
|
+
sigma_xsec = np.zeros(shape=(self._nlayers, wngrid.shape[0]))
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
for specie_idx, s in enumerate(self._species):
|
|
274
|
+
wn = self._Qext_wn[specie_idx]
|
|
275
|
+
Rmean = self._mie_particle_mean_radius[specie_idx]
|
|
276
|
+
|
|
277
|
+
## GET A LOG DISTRIBUTION OF THE PARTICLE RADIUS
|
|
278
|
+
if self._mie_particle_radius_distribution == 'budaj': ## This distribution can be found in Budaj et al. 2015
|
|
279
|
+
LogRsigma = 0.2 ## since the distribution is fixed in width, this can be set to approx 0.2 for the sampling
|
|
280
|
+
radii_log = np.linspace(10**(np.log10(Rmean)+self._Dsampling*LogRsigma), 10**(np.log10(Rmean)-self._Dsampling*LogRsigma), self._Nsampling)
|
|
281
|
+
weights = ((radii_log/Rmean)**6)*np.exp(-6*radii_log/Rmean)
|
|
282
|
+
elif self._mie_particle_radius_distribution == 'deirmendjian': ## This distribution can be found in Deirmendjian 1964 (modified Gamma distribution)
|
|
283
|
+
LogRsigma = self._mie_particle_std_radius[specie_idx]
|
|
284
|
+
radii_log = np.linspace(10**(np.log10(Rmean)+self._Dsampling*LogRsigma), 10**(np.log10(Rmean)-self._Dsampling*LogRsigma), self._Nsampling)
|
|
285
|
+
weights = self._mie_particle_paramA[specie_idx]*(radii_log**self._mie_particle_paramB[specie_idx])*np.exp(-self._mie_particle_paramC[specie_idx]*(radii_log**self._mie_particle_paramD[specie_idx]))
|
|
286
|
+
else: ## This is simply a normal distribution.
|
|
287
|
+
LogRsigma = self._mie_particle_std_radius[specie_idx]
|
|
288
|
+
radii_log = np.linspace(10**(np.log10(Rmean)+self._Dsampling*LogRsigma), 10**(np.log10(Rmean)-self._Dsampling*LogRsigma), self._Nsampling)
|
|
289
|
+
weights = stats.norm.pdf(np.log10(radii_log), np.log10(Rmean), LogRsigma)
|
|
290
|
+
Qexts = []
|
|
291
|
+
|
|
292
|
+
for radius in radii_log:
|
|
293
|
+
idx = np.searchsorted(self._radius_grid[specie_idx], radius) - 1
|
|
294
|
+
|
|
295
|
+
R1 = self._radius_grid[specie_idx][int(idx)]
|
|
296
|
+
R2 = self._radius_grid[specie_idx][int(idx)+1]
|
|
297
|
+
delta_R = R1 - R2
|
|
298
|
+
|
|
299
|
+
Q1_arr = self._Qext[specie_idx][int(idx)] # shape: (n_wavelengths,)
|
|
300
|
+
Q2_arr = self._Qext[specie_idx][int(idx)+1]
|
|
301
|
+
|
|
302
|
+
a = (Q1_arr - Q2_arr) / delta_R
|
|
303
|
+
b = Q1_arr - a * R1
|
|
304
|
+
|
|
305
|
+
# Interpolate at current log radius
|
|
306
|
+
Qexts.append(a * radius + b)
|
|
307
|
+
|
|
308
|
+
Qexts = np.array(Qexts) * np.power(radii_log[:, np.newaxis] * 1e3, 2) # As Qext was coomputed with radii in mm the radii here also needs to be in mm not um.
|
|
309
|
+
Qext_mean = np.average(Qexts, axis=0, weights=weights)
|
|
310
|
+
Qext_int = np.interp(wngrid, wn[::-1], Qext_mean[::-1], left=0, right=0)
|
|
311
|
+
sigma_mie = np.zeros((len(wngrid)))
|
|
312
|
+
|
|
313
|
+
sigma_mie[Qext_int!=0] = Qext_int[Qext_int!=0]* np.pi * 1e-18
|
|
314
|
+
## So here sigma_mie is in m2 (nm2 to m2 conversion is 1e-18)
|
|
315
|
+
|
|
316
|
+
if self._mie_midP[specie_idx] == -1:
|
|
317
|
+
bottom_pressure = pressure_profile[0]
|
|
318
|
+
top_pressure = pressure_profile[-1]
|
|
319
|
+
else:
|
|
320
|
+
bottom_pressure = 10**(np.log10(self._mie_midP[specie_idx]) + self._mie_rangeP[specie_idx]/2)
|
|
321
|
+
top_pressure = 10**(np.log10(self._mie_midP[specie_idx]) - self._mie_rangeP[specie_idx]/2)
|
|
322
|
+
|
|
323
|
+
cloud_filter = (pressure_profile <= bottom_pressure) & \
|
|
324
|
+
(pressure_profile >= top_pressure)
|
|
325
|
+
|
|
326
|
+
sigma_xsec_int = np.zeros(shape=(self._nlayers, wngrid.shape[0]))
|
|
327
|
+
|
|
328
|
+
## This line implied that self._mie_particle_mix_ratio is expressed in m-3
|
|
329
|
+
if self._particle_alt_distib == 'exp_decay':
|
|
330
|
+
## if we want it with exp decay style Whitten et al. 2008 / Attreya et al. 2005
|
|
331
|
+
decay = self._particle_alt_decay[specie_idx]
|
|
332
|
+
#mix = self._mie_particle_mix_ratio[idx]*(1-np.exp(decay*(pressure_profile-top_pressure)/(bottom_pressure-top_pressure)))
|
|
333
|
+
mix = self._mie_particle_mix_ratio[specie_idx]*(press/bottom_pressure)**(- decay)
|
|
334
|
+
sigma_xsec_int[cloud_filter, :] = sigma_mie[None] * mix[cloud_filter, None]
|
|
335
|
+
else:
|
|
336
|
+
sigma_xsec_int[cloud_filter, ...] = sigma_mie * self._mie_particle_mix_ratio[specie_idx]
|
|
337
|
+
|
|
338
|
+
sigma_xsec += sigma_xsec_int
|
|
339
|
+
|
|
340
|
+
self.sigma_xsec = sigma_xsec
|
|
341
|
+
|
|
342
|
+
self.debug('final xsec %s', self.sigma_xsec)
|
|
343
|
+
|
|
344
|
+
yield 'PyMieScattGridExt', sigma_xsec
|
|
345
|
+
|
|
346
|
+
def write(self, output):
|
|
347
|
+
contrib = super().write(output)
|
|
348
|
+
|
|
349
|
+
if self._mie_particle_mean_radius is not None:
|
|
350
|
+
contrib.write_array('particle_mean_radius', np.array(self._mie_particle_mean_radius))
|
|
351
|
+
if self._mie_particle_std_radius is not None:
|
|
352
|
+
contrib.write_array('particle_std_radius', np.array(self._mie_particle_std_radius))
|
|
353
|
+
contrib.write_array('particle_mix_ratio', np.array(self._mie_particle_mix_ratio))
|
|
354
|
+
contrib.write_array('particle_midP', np.array(self._mie_midP))
|
|
355
|
+
contrib.write_array('particle_rangeP', np.array(self._mie_rangeP))
|
|
356
|
+
contrib.write_string_array('cloud_species', self._species)
|
|
357
|
+
contrib.write_scalar('radius_Nsampling', self._Nsampling)
|
|
358
|
+
contrib.write_scalar('radius_Dsampling', self._Dsampling)
|
|
359
|
+
contrib.write_scalar('mie_nMedium', self._mie_nMedium)
|
|
360
|
+
return contrib
|
|
361
|
+
|
|
362
|
+
@classmethod
|
|
363
|
+
def input_keywords(self):
|
|
364
|
+
return ['PyMieScattGridExtinction', ]
|
|
365
|
+
|
|
366
|
+
BIBTEX_ENTRIES = [
|
|
367
|
+
"""
|
|
368
|
+
@BOOK{1983asls.book.....B,
|
|
369
|
+
author = {{Bohren}, Craig F. and {Huffman}, Donald R.},
|
|
370
|
+
title = "{Absorption and scattering of light by small particles}",
|
|
371
|
+
year = 1983,
|
|
372
|
+
adsurl = {https://ui.adsabs.harvard.edu/abs/1983asls.book.....B},
|
|
373
|
+
adsnote = {Provided by the SAO/NASA Astrophysics Data System}
|
|
374
|
+
}
|
|
375
|
+
@ARTICLE{2026A&A...707A.127V,
|
|
376
|
+
author = {{Voyer}, M. and {Changeat}, Q.},
|
|
377
|
+
title = "{Precomputed aerosol extinction, scattering, and asymmetry grids for scalable atmospheric retrievals}",
|
|
378
|
+
journal = {Astronomy and Astrophysics},
|
|
379
|
+
keywords = {radiative transfer, methods: numerical, planets and satellites: atmospheres, planets and satellites: gaseous planets, Earth and Planetary Astrophysics, Instrumentation and Methods for Astrophysics},
|
|
380
|
+
year = 2026,
|
|
381
|
+
month = mar,
|
|
382
|
+
volume = {707},
|
|
383
|
+
eid = {A127},
|
|
384
|
+
pages = {A127},
|
|
385
|
+
doi = {10.1051/0004-6361/202558469},
|
|
386
|
+
archivePrefix = {arXiv},
|
|
387
|
+
eprint = {2601.14177},
|
|
388
|
+
primaryClass = {astro-ph.EP},
|
|
389
|
+
adsurl = {https://ui.adsabs.harvard.edu/abs/2026A&A...707A.127V},
|
|
390
|
+
adsnote = {Provided by the SAO/NASA Astrophysics Data System}
|
|
391
|
+
}
|
|
392
|
+
""",
|
|
393
|
+
]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: taurex-pcq
|
|
3
|
+
Version: 1.0
|
|
4
|
+
Summary: A TauREx plugin implementing Pre Computed Qext grids for cloud models
|
|
5
|
+
Author-email: Maël Voyer <mael.voyer@cea.fr>
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: taurex,exoplanets,retrieval,atmospheres,jwst
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
14
|
+
Requires-Python: >=3.10
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: numpy
|
|
18
|
+
Requires-Dist: taurex
|
|
19
|
+
Requires-Dist: numba
|
|
20
|
+
Requires-Dist: scipy
|
|
21
|
+
Requires-Dist: h5py
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build; extra == "dev"
|
|
24
|
+
Requires-Dist: twine; extra == "dev"
|
|
25
|
+
Requires-Dist: pytest; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# Faster clouds for TauREx 3
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
This plugin provides **a new nethod to inclue aerosols** in [TauREx 3](https://github.com/ucl-exoplanets/TauREx3_public), extending the TauREx-PyMieScatt plugin. It significantly speeds up the cloud models by using precomputed extinction efficiency (`Q_ext`) grids. TauREx-PCQ also considerably improves the computation scaling with the number of clouds in the models. The speed-ups for single cloud retrievals are betwwen 1.4 and 2.7. Although, a single-cloud retrieval using Qext grids achieved a speed-up of 1.4, the same retrieval with four clouds became 17 times faster than the corresponding retrieval using direct Mie calculations.
|
|
32
|
+
The grids details and validation can be found in Voyer & Changeat (2026), if you use TauREx-PCQ or the grids please cite this paper. The species already available are Mg2SiO4, MgSiO3 (amorph sol-gel and amorph glass), SiO2 (alpha and amorph), SiO, the Titan tholins and water ice. They can be found at: [10.5281/zenodo.17456673](https://doi.org/10.5281/zenodo.17456673) .
|
|
33
|
+
|
|
34
|
+
For any inquiries, please contact: mael.voyer@u-paris.fr
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 🔧 Features
|
|
39
|
+
|
|
40
|
+
- ✅ Compatible with `transit` and `emmsion` models.
|
|
41
|
+
- ✅ Works with any aerosol specie given that the user provides a `.h5` file with :
|
|
42
|
+
|
|
43
|
+
- A `radius_grid` dataset with the particule sizes in microns ( length `a` ).
|
|
44
|
+
- A `wavenumber_grid` dataset with the wavenumber at which the `Q_ext` were computed in cm-1 ( length `b` )
|
|
45
|
+
- A `Qext_grid` dataset with the computed `Q_ext` from PyMieScat ( length (`a`, `b`) )
|
|
46
|
+
|
|
47
|
+
## As an extension of TauREx-PyMieScatt, this pulgin includes the same capabilities
|
|
48
|
+
|
|
49
|
+
- ✅ **Supports multiple particle size distributions:**
|
|
50
|
+
- `normal` (log-normal)
|
|
51
|
+
- `budaj` (2015)
|
|
52
|
+
- `deirmendjian` (1964)
|
|
53
|
+
- ✅ **Multiple species and per-species fitting**
|
|
54
|
+
- ✅ **Particle decay with altitude** (`exp_decay` based on Whitten 2008 / Atreya 2005)
|
|
55
|
+
- ✅ **Computes exctinction** using the species optical constant via **Effective Medium Theory (Bohren & Huffman 1983)**
|
|
56
|
+
- ✅ **Multiple fittable parameters** for TauREx retrievals
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 🔧 Model Parameters
|
|
61
|
+
|
|
62
|
+
| Name | Description |
|
|
63
|
+
|------|-------------|
|
|
64
|
+
| `species` | Your name for the species included through the `mie_species_path` parameter. This name will be used as suffixes added to the other parameters to distinguish between included species. |
|
|
65
|
+
| `mie_species_path` | Paths to the `Q_ext` grids of the aerosols you want to include |
|
|
66
|
+
| `mie_particle_radius_distribution` | `"normal"`, `"budaj"`, or `"deirmendjian"` |
|
|
67
|
+
| `mie_particle_mean_radius` | Mean particle radius (µm) |
|
|
68
|
+
| `mie_particle_logstd_radius` | Log-normal std dev (for `"normal"` distribution) |
|
|
69
|
+
| `mie_particle_paramA/B/C/D` | Parameters for Deirmendjian distribution |
|
|
70
|
+
| `mie_particle_mix_ratio` | Number density (molecules/m³) |
|
|
71
|
+
| `mie_midP` | Pressure at cloud center (Pa) |
|
|
72
|
+
| `mie_rangeP` | Extend of the clouds in log scale around `mie_midP`. If `mie_midP` = 1e5 Pa and `mie_rangeP` = 1 then clouds extend from 1e6 to 1e4 Pa |
|
|
73
|
+
| `mie_particle_altitude_distrib` | Currently supports `'exp_decay'` or `'linear'` |
|
|
74
|
+
| `mie_particle_altitude_decay` | Decay exponent per species e.g `-5` |
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## 💡 Usage Example in a TauREx parameter file or 'parfile'
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
[Model]
|
|
82
|
+
model_type = transit
|
|
83
|
+
|
|
84
|
+
[[PyMieScattGridExtinction]]
|
|
85
|
+
|
|
86
|
+
species = SiO, Mg2SiO4_glass, custom_molecule
|
|
87
|
+
mie_species_path = path_to_SiO.h5 , path_to_Mg2SiO4_glass.h5 , path_to_custom_molecule.h5 #e.g. You can use the optical constant from Kitzmann and Heng 2018
|
|
88
|
+
mie_particle_radius_distribution = budaj
|
|
89
|
+
mie_particle_mean_radius = 0.1, 0.4 , 10
|
|
90
|
+
mie_midP = 1e5, 1e2, 1
|
|
91
|
+
mie_rangeP = 3 , 1 , 2
|
|
92
|
+
mie_particle_mix_ratio = 1e5, 1e8 , 10e3
|
|
93
|
+
mie_particle_radius_Nsampling = 5
|
|
94
|
+
mie_particle_altitude_distrib = linear
|
|
95
|
+
```
|
|
96
|
+
---
|
|
97
|
+
## Limitations
|
|
98
|
+
|
|
99
|
+
As the `Q_ext` are computed for a range of radii between 1 nm and 30 microns, it is strongly recomended that the `mie_particle_mean_radius` prior does not extend beyond this range. Any radius outside of the range will use the `Q_ext` of the closest radius present in the grid.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
src/taurex_pcq/__init__.py
|
|
5
|
+
src/taurex_pcq.egg-info/PKG-INFO
|
|
6
|
+
src/taurex_pcq.egg-info/SOURCES.txt
|
|
7
|
+
src/taurex_pcq.egg-info/dependency_links.txt
|
|
8
|
+
src/taurex_pcq.egg-info/entry_points.txt
|
|
9
|
+
src/taurex_pcq.egg-info/requires.txt
|
|
10
|
+
src/taurex_pcq.egg-info/top_level.txt
|
|
11
|
+
src/taurex_pcq/contributions/__init__.py
|
|
12
|
+
src/taurex_pcq/contributions/pymiescatt_grid.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
taurex_pcq
|