musica 0.11.1.1__cp312-cp312-win_amd64.whl → 0.14.2__cp312-cp312-win_amd64.whl
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.
- musica/__init__.py +23 -3
- musica/_musica.cp312-win_amd64.pyd +0 -0
- musica/_version.py +1 -1
- musica/backend.py +58 -0
- musica/carma/__init__.py +20 -0
- musica/carma/carma.py +1727 -0
- musica/constants.py +3 -0
- musica/cuda.py +13 -0
- musica/examples/__init__.py +1 -0
- musica/examples/carma_aluminum.py +124 -0
- musica/examples/carma_sulfate.py +246 -0
- musica/examples/examples.py +165 -0
- musica/examples/sulfate_box_model.py +439 -0
- musica/examples/ts1_latin_hypercube.py +245 -0
- musica/main.py +128 -0
- musica/mechanism_configuration/__init__.py +18 -0
- musica/mechanism_configuration/ancillary.py +6 -0
- musica/mechanism_configuration/arrhenius.py +149 -0
- musica/mechanism_configuration/branched.py +140 -0
- musica/mechanism_configuration/emission.py +82 -0
- musica/mechanism_configuration/first_order_loss.py +90 -0
- musica/mechanism_configuration/mechanism.py +93 -0
- musica/mechanism_configuration/phase.py +58 -0
- musica/mechanism_configuration/phase_species.py +58 -0
- musica/mechanism_configuration/photolysis.py +98 -0
- musica/mechanism_configuration/reaction_component.py +54 -0
- musica/mechanism_configuration/reactions.py +32 -0
- musica/mechanism_configuration/species.py +65 -0
- musica/mechanism_configuration/surface.py +98 -0
- musica/mechanism_configuration/taylor_series.py +136 -0
- musica/mechanism_configuration/ternary_chemical_activation.py +160 -0
- musica/mechanism_configuration/troe.py +160 -0
- musica/mechanism_configuration/tunneling.py +126 -0
- musica/mechanism_configuration/user_defined.py +99 -0
- musica/mechanism_configuration/utils.py +10 -0
- musica/micm/__init__.py +10 -0
- musica/micm/conditions.py +49 -0
- musica/micm/micm.py +135 -0
- musica/micm/solver.py +8 -0
- musica/micm/solver_result.py +24 -0
- musica/micm/state.py +220 -0
- musica/micm/utils.py +18 -0
- musica/tuvx/__init__.py +11 -0
- musica/tuvx/grid.py +98 -0
- musica/tuvx/grid_map.py +167 -0
- musica/tuvx/profile.py +130 -0
- musica/tuvx/profile_map.py +167 -0
- musica/tuvx/radiator.py +95 -0
- musica/tuvx/radiator_map.py +173 -0
- musica/tuvx/tuvx.py +283 -0
- musica-0.14.2.dist-info/DELVEWHEEL +2 -0
- {musica-0.11.1.1.dist-info → musica-0.14.2.dist-info}/METADATA +146 -63
- musica-0.14.2.dist-info/RECORD +104 -0
- {musica-0.11.1.1.dist-info → musica-0.14.2.dist-info}/WHEEL +1 -1
- musica-0.14.2.dist-info/entry_points.txt +3 -0
- musica-0.14.2.dist-info/licenses/AUTHORS.md +59 -0
- musica.libs/libaws-c-auth-0a61a643442f1c0912920b37d9fb0be5.dll +0 -0
- musica.libs/libaws-c-cal-eaafa5905de6c9ba274eb8737e6087dd.dll +0 -0
- musica.libs/libaws-c-common-b4aa4468297ae8e1664f9380a5510317.dll +0 -0
- musica.libs/libaws-c-compression-9f997952aeae03067122ca493c9081b5.dll +0 -0
- musica.libs/libaws-c-event-stream-fe9cc8e1692f60c2b5694a8959dbd7c3.dll +0 -0
- musica.libs/libaws-c-http-4a9d50ba6ad8882f5267ef89e5e4103a.dll +0 -0
- musica.libs/libaws-c-io-e454f1c7a44e77f8c957a016888754be.dll +0 -0
- musica.libs/libaws-c-mqtt-67c5fc291740f5cbc5e53fb767e93226.dll +0 -0
- musica.libs/libaws-c-s3-206db4af6e1a95637b1921ea596603b9.dll +0 -0
- musica.libs/libaws-c-sdkutils-5c9c62dafb8b774cd4a3386f95ef428d.dll +0 -0
- musica.libs/libaws-checksums-7e50fe01b862214958f4d2ab4215fde5.dll +0 -0
- musica.libs/libaws-cpp-sdk-core-7a9ba9c045ee16f5262e955d96865718.dll +0 -0
- musica.libs/libaws-cpp-sdk-s3-4eebff3923c6d250fb508da3c990e0ae.dll +0 -0
- musica.libs/libaws-crt-cpp-3173f1e6f504a96d88e8dbf9e04b3b14.dll +0 -0
- musica.libs/libbrotlicommon-c62c08223e450dfc2fff33c752cc2285.dll +0 -0
- musica.libs/libbrotlidec-ccde7c3978eb1d2e052b193f2968d30a.dll +0 -0
- musica.libs/libbz2-1-669a4bf9266d5f020e843aa5fd75b93c.dll +0 -0
- musica.libs/libcrypto-3-x64-237eeb55505d067eab5e0b886e519387.dll +0 -0
- musica.libs/libcurl-4-bdf865458887dc1235b192ec83729214.dll +0 -0
- musica.libs/libgcc_s_seh-1-5a3153f12338f79fbbb7bf095fc5cef1.dll +0 -0
- musica.libs/libgfortran-5-90848e0eacdecce3a9005faf5aaec7e7.dll +0 -0
- musica.libs/libgomp-1-b8afcf09fecd2f6f01e454c9a5f2c690.dll +0 -0
- musica.libs/libhdf5-320-eec6c8ba2fdde30d365786ffbff40989.dll +0 -0
- musica.libs/libhdf5_hl-320-7e26e1caaad6be4082d728cf08ab2de4.dll +0 -0
- musica.libs/libiconv-2-b37d1b4acab5310c4e4f6e2a961d1464.dll +0 -0
- musica.libs/libidn2-0-d17600177f3b4cd2521d595b3472d240.dll +0 -0
- musica.libs/libintl-8-e4d4ca6b37338fbb0a8c1246afa7258f.dll +0 -0
- musica.libs/liblzma-5-bd95aa0fda6e7c8e41b3843d6fc2942c.dll +0 -0
- musica.libs/libnetcdf-0623e518145bddd30cc615b6d7f2f9c1.dll +0 -0
- musica.libs/libnetcdff-7-982cb7ee026b78f05a79d00e735f91d1.dll +0 -0
- musica.libs/libnghttp2-14-6d49ed806389b4892bcf29c6ed6e3984.dll +0 -0
- musica.libs/libnghttp3-9-d3c9b57d760f6dae7d6a067a68126b84.dll +0 -0
- musica.libs/libngtcp2-16-a43356e6376d41ce4238e2c55581636a.dll +0 -0
- musica.libs/libngtcp2_crypto_ossl-0-b37121badf25a552e5654f27bf6ff093.dll +0 -0
- musica.libs/libopenblas-a16595c3cae114c5c7304aa8bb3c1272.dll +0 -0
- musica.libs/libpsl-5-4368d4c2412410a4a14f3e7f3227e295.dll +0 -0
- musica.libs/libquadmath-0-4edeffe0a60c96360445d33a1876dbda.dll +0 -0
- musica.libs/libssh2-1-f407a2b50419bd904c7eb2c101ae81ea.dll +0 -0
- musica.libs/libssl-3-x64-d2e43d36e6f87f6f1645717cd0871f86.dll +0 -0
- musica.libs/libstdc++-6-83061aaccaf8df77a3b584efef12bc7c.dll +0 -0
- musica.libs/libsz-2-d12f3d26417507ec8dea9964f9fe36a1.dll +0 -0
- musica.libs/libunistring-5-0473d7a71d94f08292beed694c34f7d1.dll +0 -0
- musica.libs/libwinpthread-1-9157bac12a85fb717fa3d2bf6712631a.dll +0 -0
- musica.libs/libxml2-16-7fe545d280fdef922282226eef91571f.dll +0 -0
- musica.libs/libzip-62d3c877b7842bc509fc000316a4731b.dll +0 -0
- musica.libs/libzstd-a25427164f8775046eb8ce488d7d0884.dll +0 -0
- musica.libs/zlib1-1dc85208162ee57fe97e892bb5160fe9.dll +0 -0
- _musica.cp312-win_amd64.pyd +0 -0
- lib/musica.lib +0 -0
- lib/yaml-cpp.lib +0 -0
- musica/CMakeLists.txt +0 -47
- musica/binding.cpp +0 -19
- musica/mechanism_configuration.cpp +0 -519
- musica/mechanism_configuration.py +0 -1291
- musica/musica.cpp +0 -214
- musica/test/examples/v0/config.json +0 -7
- musica/test/examples/v0/config.yaml +0 -3
- musica/test/examples/v0/reactions.json +0 -193
- musica/test/examples/v0/reactions.yaml +0 -142
- musica/test/examples/v0/species.json +0 -40
- musica/test/examples/v0/species.yaml +0 -19
- musica/test/examples/v1/full_configuration.json +0 -434
- musica/test/examples/v1/full_configuration.yaml +0 -271
- musica/test/test_analytical.py +0 -323
- musica/test/test_chapman.py +0 -123
- musica/test/test_parser.py +0 -693
- musica/test/tuvx.py +0 -10
- musica/tools/prepare_build_environment_linux.sh +0 -41
- musica/tools/prepare_build_environment_windows.sh +0 -22
- musica/tools/repair_wheel_gpu.sh +0 -25
- musica/types.py +0 -362
- musica-0.11.1.1.dist-info/RECORD +0 -30
- {musica-0.11.1.1.dist-info → musica-0.14.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Copyright (C) 2023-2025 University Corporation for Atmospheric Research
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
"""
|
|
4
|
+
TUV-x RadiatorMap class.
|
|
5
|
+
|
|
6
|
+
This module provides a class for managing collections of TUV-x radiators.
|
|
7
|
+
The RadiatorMap class allows dictionary-style access to radiators using their names as keys.
|
|
8
|
+
|
|
9
|
+
Note: TUV-x is only available on macOS and Linux platforms.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from typing import Iterator
|
|
13
|
+
from .. import backend
|
|
14
|
+
from .radiator import Radiator
|
|
15
|
+
|
|
16
|
+
_backend = backend.get_backend()
|
|
17
|
+
|
|
18
|
+
RadiatorMap = _backend._tuvx._RadiatorMap if backend.tuvx_available() else None
|
|
19
|
+
|
|
20
|
+
if backend.tuvx_available():
|
|
21
|
+
original_init = RadiatorMap.__init__
|
|
22
|
+
|
|
23
|
+
def __init__(self, **kwargs):
|
|
24
|
+
"""Initialize a RadiatorMap instance.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
**kwargs: Additional arguments passed to the C++ constructor
|
|
28
|
+
"""
|
|
29
|
+
original_init(self, **kwargs)
|
|
30
|
+
|
|
31
|
+
RadiatorMap.__init__ = __init__
|
|
32
|
+
|
|
33
|
+
def __str__(self):
|
|
34
|
+
"""User-friendly string representation."""
|
|
35
|
+
return f"RadiatorMap(num_radiators={len(self)})"
|
|
36
|
+
|
|
37
|
+
RadiatorMap.__str__ = __str__
|
|
38
|
+
|
|
39
|
+
def __repr__(self):
|
|
40
|
+
"""Detailed string representation for debugging."""
|
|
41
|
+
radiator_details = []
|
|
42
|
+
for i in range(len(self)):
|
|
43
|
+
radiator = self.get_radiator_by_index(i)
|
|
44
|
+
radiator_details.append(f"{radiator.name}")
|
|
45
|
+
return f"RadiatorMap(radiators={radiator_details})"
|
|
46
|
+
|
|
47
|
+
RadiatorMap.__repr__ = __repr__
|
|
48
|
+
|
|
49
|
+
def __len__(self):
|
|
50
|
+
"""Return the number of radiators in the map."""
|
|
51
|
+
return self.get_number_of_radiators()
|
|
52
|
+
|
|
53
|
+
RadiatorMap.__len__ = __len__
|
|
54
|
+
|
|
55
|
+
def __bool__(self):
|
|
56
|
+
"""Return True if the map has any radiators."""
|
|
57
|
+
return len(self) > 0
|
|
58
|
+
|
|
59
|
+
RadiatorMap.__bool__ = __bool__
|
|
60
|
+
|
|
61
|
+
def __getitem__(self, key) -> Radiator:
|
|
62
|
+
"""Get a radiator by name.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
key: Name of the radiator to retrieve
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Radiator instance corresponding to the given name
|
|
69
|
+
|
|
70
|
+
Raises:
|
|
71
|
+
KeyError: If no radiator with the given name exists
|
|
72
|
+
"""
|
|
73
|
+
if not isinstance(key, str):
|
|
74
|
+
raise TypeError("Radiator name must be a string.")
|
|
75
|
+
try:
|
|
76
|
+
radiator = self.get_radiator(key)
|
|
77
|
+
if radiator is None:
|
|
78
|
+
raise KeyError(f"Radiator with name '{key}' not found.")
|
|
79
|
+
return radiator
|
|
80
|
+
except Exception as e:
|
|
81
|
+
raise KeyError(f"No radiator found with name='{key}'") from e
|
|
82
|
+
|
|
83
|
+
RadiatorMap.__getitem__ = __getitem__
|
|
84
|
+
|
|
85
|
+
def __setitem__(self, key: str, radiator: Radiator):
|
|
86
|
+
"""Set a radiator in the map by name.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
key: Name of the radiator to set
|
|
90
|
+
radiator: Radiator instance to associate with the given name
|
|
91
|
+
"""
|
|
92
|
+
if not isinstance(key, str):
|
|
93
|
+
raise TypeError("Radiator name must be a string.")
|
|
94
|
+
if not isinstance(radiator, Radiator):
|
|
95
|
+
raise TypeError("Value must be a Radiator instance.")
|
|
96
|
+
if radiator.name != key:
|
|
97
|
+
raise ValueError("Radiator name does not match the key.")
|
|
98
|
+
self.add_radiator(radiator)
|
|
99
|
+
|
|
100
|
+
RadiatorMap.__setitem__ = __setitem__
|
|
101
|
+
|
|
102
|
+
def __iter__(self) -> Iterator[Radiator]:
|
|
103
|
+
"""Iterator over the radiators in the map.
|
|
104
|
+
|
|
105
|
+
Yields:
|
|
106
|
+
Radiator instances in the map
|
|
107
|
+
"""
|
|
108
|
+
for i in range(len(self)):
|
|
109
|
+
yield self.get_radiator_by_index(i).name
|
|
110
|
+
|
|
111
|
+
RadiatorMap.__iter__ = __iter__
|
|
112
|
+
|
|
113
|
+
def __contains__(self, key: str) -> bool:
|
|
114
|
+
"""Check if a radiator with the given name exists in the map.
|
|
115
|
+
|
|
116
|
+
Args:
|
|
117
|
+
key: Name of the radiator to check
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
True if a radiator with the given name exists, False otherwise
|
|
121
|
+
"""
|
|
122
|
+
if not isinstance(key, str):
|
|
123
|
+
return False
|
|
124
|
+
try:
|
|
125
|
+
radiator = self.get_radiator(str(key))
|
|
126
|
+
return radiator is not None
|
|
127
|
+
except (ValueError, KeyError):
|
|
128
|
+
return False
|
|
129
|
+
|
|
130
|
+
RadiatorMap.__contains__ = __contains__
|
|
131
|
+
|
|
132
|
+
def clear(self):
|
|
133
|
+
"""Remove all radiators from the map."""
|
|
134
|
+
num_radiators = len(self)
|
|
135
|
+
for _ in range(num_radiators):
|
|
136
|
+
self.remove_radiator_by_index(0)
|
|
137
|
+
|
|
138
|
+
RadiatorMap.clear = clear
|
|
139
|
+
|
|
140
|
+
def items(self):
|
|
141
|
+
"""Iterator over (name, radiator) pairs in the map.
|
|
142
|
+
|
|
143
|
+
Yields:
|
|
144
|
+
Tuples of (radiator_name, Radiator instance)
|
|
145
|
+
"""
|
|
146
|
+
for i in range(len(self)):
|
|
147
|
+
radiator = self.get_radiator_by_index(i)
|
|
148
|
+
yield (radiator.name, radiator)
|
|
149
|
+
|
|
150
|
+
RadiatorMap.items = items
|
|
151
|
+
|
|
152
|
+
def keys(self):
|
|
153
|
+
"""Iterator over radiator names in the map.
|
|
154
|
+
|
|
155
|
+
Yields:
|
|
156
|
+
Radiator names as strings
|
|
157
|
+
"""
|
|
158
|
+
for i in range(len(self)):
|
|
159
|
+
radiator = self.get_radiator_by_index(i)
|
|
160
|
+
yield radiator.name
|
|
161
|
+
|
|
162
|
+
RadiatorMap.keys = keys
|
|
163
|
+
|
|
164
|
+
def values(self):
|
|
165
|
+
"""Iterator over Radiator instances in the map.
|
|
166
|
+
|
|
167
|
+
Yields:
|
|
168
|
+
Radiator instances
|
|
169
|
+
"""
|
|
170
|
+
for i in range(len(self)):
|
|
171
|
+
yield self.get_radiator_by_index(i)
|
|
172
|
+
|
|
173
|
+
RadiatorMap.values = values
|
musica/tuvx/tuvx.py
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TUV-x photolysis calculator Python interface.
|
|
3
|
+
|
|
4
|
+
This module provides a simplified Python interface to the TUV-x photolysis calculator.
|
|
5
|
+
It allows users to create a TUV-x instance from a JSON configuration file and
|
|
6
|
+
calculate photolysis rates and heating rates.
|
|
7
|
+
|
|
8
|
+
Note: TUV-x is only available on macOS and Linux platforms.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import json
|
|
13
|
+
import tempfile
|
|
14
|
+
from typing import Dict, Optional, Tuple
|
|
15
|
+
import numpy as np
|
|
16
|
+
from .. import backend
|
|
17
|
+
|
|
18
|
+
_backend = backend.get_backend()
|
|
19
|
+
|
|
20
|
+
# Import the GridMap class from the backend
|
|
21
|
+
if backend.tuvx_available():
|
|
22
|
+
from .grid_map import GridMap
|
|
23
|
+
from .profile import Profile
|
|
24
|
+
from .profile_map import ProfileMap
|
|
25
|
+
from .radiator import Radiator
|
|
26
|
+
from .radiator_map import RadiatorMap
|
|
27
|
+
else:
|
|
28
|
+
GridMap = None
|
|
29
|
+
Profile = None
|
|
30
|
+
ProfileMap = None
|
|
31
|
+
Radiator = None
|
|
32
|
+
RadiatorMap = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TUVX:
|
|
36
|
+
"""
|
|
37
|
+
A Python interface to the TUV-x photolysis calculator.
|
|
38
|
+
|
|
39
|
+
This class provides a simplified interface that only requires a JSON/YAML configuration
|
|
40
|
+
to set up and run TUV-x calculations. All parameters (solar zenith angle,
|
|
41
|
+
earth-sun distance, atmospheric profiles, etc.) are specified in the JSON/YAML configuration.
|
|
42
|
+
|
|
43
|
+
The configuration can be in a file or provided as a string. Exactly one of `config_path` or
|
|
44
|
+
`config_string` must be provided.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
def __init__(self,
|
|
48
|
+
grid_map: GridMap,
|
|
49
|
+
profile_map: ProfileMap,
|
|
50
|
+
radiator_map: RadiatorMap,
|
|
51
|
+
config_path: Optional[str] = None,
|
|
52
|
+
config_string: Optional[str] = None):
|
|
53
|
+
"""
|
|
54
|
+
Initialize a TUV-x instance from a configuration file.
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
grid_map: GridMap instance containing grid definitions (height, wavelength)
|
|
58
|
+
profile_map: ProfileMap instance containing atmospheric profiles (temperature, species concentrations, surface albedo, ET flux)
|
|
59
|
+
radiator_map: RadiatorMap instance containing radiator definitions (optically active species)
|
|
60
|
+
config_path: Path to the JSON configuration file
|
|
61
|
+
config_string: JSON configuration as a string
|
|
62
|
+
|
|
63
|
+
Raises:
|
|
64
|
+
FileNotFoundError: If the configuration file doesn't exist
|
|
65
|
+
ValueError: If TUV-x initialization fails or TUVX is not available
|
|
66
|
+
"""
|
|
67
|
+
if not backend.tuvx_available():
|
|
68
|
+
raise ValueError("TUV-x backend is not available.")
|
|
69
|
+
|
|
70
|
+
if (config_path is None and config_string is None) or \
|
|
71
|
+
(config_path is not None and config_string is not None):
|
|
72
|
+
raise ValueError(
|
|
73
|
+
"Exactly one of config_path or config_string must be provided.")
|
|
74
|
+
|
|
75
|
+
if config_path is not None and not os.path.exists(config_path):
|
|
76
|
+
raise FileNotFoundError(
|
|
77
|
+
f"Configuration file not found: {config_path}")
|
|
78
|
+
|
|
79
|
+
if config_path is not None:
|
|
80
|
+
self._tuvx_instance = _backend._tuvx._create_tuvx_from_file(
|
|
81
|
+
config_path, grid_map, profile_map, radiator_map)
|
|
82
|
+
self._config_path = config_path
|
|
83
|
+
self._config_string = None
|
|
84
|
+
elif config_string is not None:
|
|
85
|
+
self._tuvx_instance = _backend._tuvx._create_tuvx_from_string(
|
|
86
|
+
config_string, grid_map, profile_map, radiator_map)
|
|
87
|
+
self._config_path = None
|
|
88
|
+
self._config_string = config_string
|
|
89
|
+
|
|
90
|
+
# Cache the names for efficiency
|
|
91
|
+
self._photolysis_names = None
|
|
92
|
+
self._heating_names = None
|
|
93
|
+
self._dose_names = None
|
|
94
|
+
|
|
95
|
+
def __del__(self):
|
|
96
|
+
"""Clean up the TUV-x instance."""
|
|
97
|
+
if hasattr(self, '_tuvx_instance') and self._tuvx_instance is not None:
|
|
98
|
+
_backend._tuvx._delete_tuvx(self._tuvx_instance)
|
|
99
|
+
|
|
100
|
+
@property
|
|
101
|
+
def photolysis_rate_names(self) -> dict[str, int]:
|
|
102
|
+
"""
|
|
103
|
+
Get the names of photolysis rates.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
Dictionary mapping photolysis rate names to their indices in the output arrays
|
|
107
|
+
"""
|
|
108
|
+
if self._photolysis_names is None:
|
|
109
|
+
self._photolysis_names = _backend._tuvx._get_photolysis_rate_constants_ordering(
|
|
110
|
+
self._tuvx_instance)
|
|
111
|
+
return self._photolysis_names
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def heating_rate_names(self) -> dict[str, int]:
|
|
115
|
+
"""
|
|
116
|
+
Get the names of heating rates.
|
|
117
|
+
|
|
118
|
+
Returns:
|
|
119
|
+
Dictionary mapping heating rate names to their indices in the output arrays
|
|
120
|
+
"""
|
|
121
|
+
if self._heating_names is None:
|
|
122
|
+
self._heating_names = _backend._tuvx._get_heating_rates_ordering(
|
|
123
|
+
self._tuvx_instance)
|
|
124
|
+
return self._heating_names
|
|
125
|
+
|
|
126
|
+
@property
|
|
127
|
+
def dose_rate_names(self) -> dict[str, int]:
|
|
128
|
+
"""
|
|
129
|
+
Get the names of dose rates.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Dictionary mapping dose rate names to their indices in the output arrays
|
|
133
|
+
"""
|
|
134
|
+
if self._dose_names is None:
|
|
135
|
+
self._dose_names = _backend._tuvx._get_dose_rates_ordering(
|
|
136
|
+
self._tuvx_instance)
|
|
137
|
+
return self._dose_names
|
|
138
|
+
|
|
139
|
+
def run(self, sza: float, earth_sun_distance: float) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
140
|
+
"""
|
|
141
|
+
Run the TUV-x photolysis calculator.
|
|
142
|
+
|
|
143
|
+
All parameters (solar zenith angle, Earth-Sun distance, atmospheric profiles,
|
|
144
|
+
etc.) are read from the JSON configuration file.
|
|
145
|
+
|
|
146
|
+
Args:
|
|
147
|
+
sza: Solar zenith angle in radians
|
|
148
|
+
earth_sun_distance: Earth-Sun distance in astronomical units (AU)
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
Tuple of (photolysis_rate_constants, heating_rates) as numpy arrays
|
|
152
|
+
- photolysis_rate_constants: Shape (n_layers, n_reactions) [s^-1]
|
|
153
|
+
- heating_rates: Shape (n_layers, n_heating_rates) [K s^-1]
|
|
154
|
+
- dose_rates: Shape (n_layers, n_dose_rates) [W m^-2]
|
|
155
|
+
"""
|
|
156
|
+
photolysis_rates, heating_rates, dose_rates = _backend._tuvx._run_tuvx(
|
|
157
|
+
self._tuvx_instance, sza, earth_sun_distance)
|
|
158
|
+
|
|
159
|
+
return photolysis_rates, heating_rates, dose_rates
|
|
160
|
+
|
|
161
|
+
def get_photolysis_rate_constant(
|
|
162
|
+
self,
|
|
163
|
+
reaction_name: str,
|
|
164
|
+
photolysis_rates: np.ndarray
|
|
165
|
+
) -> np.ndarray:
|
|
166
|
+
"""
|
|
167
|
+
Extract photolysis rate constants for a specific reaction.
|
|
168
|
+
|
|
169
|
+
Args:
|
|
170
|
+
reaction_name: Name of the photolysis reaction
|
|
171
|
+
photolysis_rates: Output from run() method
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
1D array of photolysis rate constants for all layers [s^-1]
|
|
175
|
+
|
|
176
|
+
Raises:
|
|
177
|
+
KeyError: If reaction_name is not found
|
|
178
|
+
"""
|
|
179
|
+
names = self.photolysis_rate_names
|
|
180
|
+
if reaction_name not in names:
|
|
181
|
+
raise KeyError(
|
|
182
|
+
f"Reaction '{reaction_name}' not found. "
|
|
183
|
+
f"Available reactions: {names}"
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
reaction_index = names[reaction_name]
|
|
187
|
+
return photolysis_rates[:, reaction_index]
|
|
188
|
+
|
|
189
|
+
def get_heating_rate(
|
|
190
|
+
self,
|
|
191
|
+
rate_name: str,
|
|
192
|
+
heating_rates: np.ndarray
|
|
193
|
+
) -> np.ndarray:
|
|
194
|
+
"""
|
|
195
|
+
Extract heating rates for a specific rate type.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
rate_name: Name of the heating rate
|
|
199
|
+
heating_rates: Output from run() method
|
|
200
|
+
|
|
201
|
+
Returns:
|
|
202
|
+
1D array of heating rates for all layers [K s^-1]
|
|
203
|
+
|
|
204
|
+
Raises:
|
|
205
|
+
KeyError: If rate_name is not found
|
|
206
|
+
"""
|
|
207
|
+
names = self.heating_rate_names
|
|
208
|
+
if rate_name not in names:
|
|
209
|
+
raise KeyError(
|
|
210
|
+
f"Heating rate '{rate_name}' not found. "
|
|
211
|
+
f"Available rates: {names}"
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
rate_index = names[rate_name]
|
|
215
|
+
return heating_rates[:, rate_index]
|
|
216
|
+
|
|
217
|
+
def get_dose_rate(
|
|
218
|
+
self,
|
|
219
|
+
rate_name: str,
|
|
220
|
+
dose_rates: np.ndarray
|
|
221
|
+
) -> np.ndarray:
|
|
222
|
+
"""
|
|
223
|
+
Extract dose rates for a specific rate type.
|
|
224
|
+
|
|
225
|
+
Args:
|
|
226
|
+
rate_name: Name of the dose rate
|
|
227
|
+
dose_rates: Output from run() method
|
|
228
|
+
|
|
229
|
+
Returns:
|
|
230
|
+
1D array of dose rates for all layers [W m^-2]
|
|
231
|
+
|
|
232
|
+
Raises:
|
|
233
|
+
KeyError: If rate_name is not found
|
|
234
|
+
"""
|
|
235
|
+
names = self.dose_rate_names
|
|
236
|
+
if rate_name not in names:
|
|
237
|
+
raise KeyError(
|
|
238
|
+
f"Dose rate '{rate_name}' not found. "
|
|
239
|
+
f"Available rates: {names}"
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
rate_index = names[rate_name]
|
|
243
|
+
return dose_rates[:, rate_index]
|
|
244
|
+
|
|
245
|
+
@staticmethod
|
|
246
|
+
def create_config_from_dict(config_dict: Dict) -> 'TUVX':
|
|
247
|
+
"""
|
|
248
|
+
Create a TUVX instance from a configuration dictionary.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
config_dict: Configuration dictionary
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
TUVX instance initialized with the configuration
|
|
255
|
+
|
|
256
|
+
Raises:
|
|
257
|
+
ValueError: If TUV-x backend is not available
|
|
258
|
+
FileNotFoundError: If required data files are not found
|
|
259
|
+
"""
|
|
260
|
+
with tempfile.NamedTemporaryFile(
|
|
261
|
+
mode='w', suffix='.json', delete=True) as temp_file:
|
|
262
|
+
json.dump(config_dict, temp_file, indent=2)
|
|
263
|
+
temp_file.flush() # Ensure all data is written to disk
|
|
264
|
+
return TUVX(temp_file.name)
|
|
265
|
+
|
|
266
|
+
@staticmethod
|
|
267
|
+
def create_config_from_json_string(json_string: str) -> 'TUVX':
|
|
268
|
+
"""
|
|
269
|
+
Create a TUVX instance from a JSON configuration string.
|
|
270
|
+
|
|
271
|
+
Args:
|
|
272
|
+
json_string: JSON configuration as string
|
|
273
|
+
|
|
274
|
+
Returns:
|
|
275
|
+
TUVX instance initialized with the configuration
|
|
276
|
+
|
|
277
|
+
Raises:
|
|
278
|
+
json.JSONDecodeError: If json_string is not valid JSON
|
|
279
|
+
ValueError: If TUV-x backend is not available
|
|
280
|
+
FileNotFoundError: If required data files are not found
|
|
281
|
+
"""
|
|
282
|
+
config_dict = json.loads(json_string)
|
|
283
|
+
return TUVX.create_config_from_dict(config_dict)
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
Version: 1.11.2
|
|
2
|
+
Arguments: ['D:\\a\\_temp\\msys64\\tmp\\cibw-run-cpdfm3e4\\cp312-win_amd64\\build\\venv\\Lib\\site-packages\\delvewheel\\__main__.py', 'repair', '--add-path', 'D:/a/_temp/msys64/ucrt64/bin', '--add-path', 'D:/a/_temp/msys64/ucrt64/lib', '--add-path', 'D:/a/_temp/msys64/mingw64/bin', '--add-path', 'D:/a/_temp/msys64/mingw64/lib', '--wheel-dir', 'D:\\a\\_temp\\msys64\\tmp\\cibw-run-cpdfm3e4\\cp312-win_amd64\\repaired_wheel', 'D:\\a\\_temp\\msys64\\tmp\\cibw-run-cpdfm3e4\\cp312-win_amd64\\built_wheel\\musica-0.14.2-cp312-cp312-win_amd64.whl']
|