musica 0.12.2__cp39-cp39-macosx_15_0_arm64.whl → 0.13.0__cp39-cp39-macosx_15_0_arm64.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.
Potentially problematic release.
This version of musica might be problematic. Click here for more details.
- musica/.dylibs/libgcc_s.1.1.dylib +0 -0
- musica/.dylibs/libgfortran.5.dylib +0 -0
- musica/.dylibs/libquadmath.0.dylib +0 -0
- musica/CMakeLists.txt +4 -0
- musica/_musica.cpython-39-darwin.so +0 -0
- musica/_version.py +1 -1
- musica/binding_common.cpp +6 -9
- musica/binding_common.hpp +17 -1
- musica/grid.cpp +206 -0
- musica/grid.py +98 -0
- musica/grid_map.cpp +117 -0
- musica/grid_map.py +167 -0
- musica/mechanism_configuration/__init__.py +18 -1
- musica/mechanism_configuration/ancillary.py +6 -0
- musica/mechanism_configuration/arrhenius.py +111 -269
- musica/mechanism_configuration/branched.py +116 -275
- musica/mechanism_configuration/emission.py +63 -52
- musica/mechanism_configuration/first_order_loss.py +73 -157
- musica/mechanism_configuration/mechanism.py +93 -0
- musica/mechanism_configuration/phase.py +44 -33
- musica/mechanism_configuration/phase_species.py +58 -0
- musica/mechanism_configuration/photolysis.py +77 -67
- musica/mechanism_configuration/reaction_component.py +54 -0
- musica/mechanism_configuration/reactions.py +17 -58
- musica/mechanism_configuration/species.py +45 -71
- musica/mechanism_configuration/surface.py +78 -74
- musica/mechanism_configuration/taylor_series.py +136 -0
- musica/mechanism_configuration/ternary_chemical_activation.py +138 -330
- musica/mechanism_configuration/troe.py +138 -330
- musica/mechanism_configuration/tunneling.py +105 -229
- musica/mechanism_configuration/user_defined.py +79 -68
- musica/mechanism_configuration.cpp +54 -162
- musica/musica.cpp +2 -5
- musica/profile.cpp +294 -0
- musica/profile.py +93 -0
- musica/profile_map.cpp +117 -0
- musica/profile_map.py +167 -0
- musica/test/examples/v1/full_configuration/full_configuration.json +91 -233
- musica/test/examples/v1/full_configuration/full_configuration.yaml +191 -290
- musica/test/integration/test_chapman.py +2 -2
- musica/test/integration/test_tuvx.py +72 -15
- musica/test/unit/test_grid.py +137 -0
- musica/test/unit/test_grid_map.py +126 -0
- musica/test/unit/test_parser.py +10 -10
- musica/test/unit/test_profile.py +169 -0
- musica/test/unit/test_profile_map.py +137 -0
- musica/test/unit/test_serializer.py +17 -16
- musica/test/unit/test_state.py +17 -4
- musica/test/unit/test_util_full_mechanism.py +78 -298
- musica/tuvx.cpp +94 -15
- musica/tuvx.py +92 -22
- musica/types.py +13 -5
- {musica-0.12.2.dist-info → musica-0.13.0.dist-info}/METADATA +14 -14
- musica-0.13.0.dist-info/RECORD +90 -0
- musica/mechanism_configuration/aqueous_equilibrium.py +0 -274
- musica/mechanism_configuration/condensed_phase_arrhenius.py +0 -309
- musica/mechanism_configuration/condensed_phase_photolysis.py +0 -88
- musica/mechanism_configuration/henrys_law.py +0 -44
- musica/mechanism_configuration/mechanism_configuration.py +0 -234
- musica/mechanism_configuration/simpol_phase_transfer.py +0 -217
- musica/mechanism_configuration/wet_deposition.py +0 -52
- musica-0.12.2.dist-info/RECORD +0 -80
- {musica-0.12.2.dist-info → musica-0.13.0.dist-info}/WHEEL +0 -0
- {musica-0.12.2.dist-info → musica-0.13.0.dist-info}/entry_points.txt +0 -0
- {musica-0.12.2.dist-info → musica-0.13.0.dist-info}/licenses/AUTHORS.md +0 -0
- {musica-0.12.2.dist-info → musica-0.13.0.dist-info}/licenses/LICENSE +0 -0
musica/tuvx.cpp
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#include "binding_common.hpp"
|
|
2
2
|
|
|
3
3
|
#include <musica/tuvx/tuvx.hpp>
|
|
4
|
+
#include <musica/util.hpp>
|
|
4
5
|
|
|
5
6
|
#include <pybind11/numpy.h>
|
|
6
7
|
#include <pybind11/pybind11.h>
|
|
@@ -13,13 +14,30 @@ void bind_tuvx(py::module_& tuvx)
|
|
|
13
14
|
tuvx.def("_get_tuvx_version", []() { return musica::TUVX::GetVersion(); }, "Get the version of the TUV-x instance");
|
|
14
15
|
|
|
15
16
|
tuvx.def(
|
|
16
|
-
"
|
|
17
|
+
"_create_tuvx_from_string",
|
|
18
|
+
[](const char* config_string)
|
|
19
|
+
{
|
|
20
|
+
try
|
|
21
|
+
{
|
|
22
|
+
auto tuvx_instance = new musica::TUVX();
|
|
23
|
+
tuvx_instance->CreateFromConfigString(config_string);
|
|
24
|
+
return reinterpret_cast<std::uintptr_t>(tuvx_instance);
|
|
25
|
+
}
|
|
26
|
+
catch (const std::exception& e)
|
|
27
|
+
{
|
|
28
|
+
throw py::value_error("Error creating TUV-x instance from config string: " + std::string(e.what()));
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"Create a TUV-x instance from a JSON/YAML configuration string");
|
|
32
|
+
|
|
33
|
+
tuvx.def(
|
|
34
|
+
"_create_tuvx_from_file",
|
|
17
35
|
[](const char* config_path)
|
|
18
36
|
{
|
|
19
37
|
try
|
|
20
38
|
{
|
|
21
39
|
auto tuvx_instance = new musica::TUVX();
|
|
22
|
-
tuvx_instance->
|
|
40
|
+
tuvx_instance->CreateFromConfigFile(config_path);
|
|
23
41
|
return reinterpret_cast<std::uintptr_t>(tuvx_instance);
|
|
24
42
|
}
|
|
25
43
|
catch (const std::exception& e)
|
|
@@ -28,7 +46,7 @@ void bind_tuvx(py::module_& tuvx)
|
|
|
28
46
|
"Error creating TUV-x instance from config file: " + std::string(config_path) + " - " + e.what());
|
|
29
47
|
}
|
|
30
48
|
},
|
|
31
|
-
"Create a TUV-x instance from a JSON configuration file");
|
|
49
|
+
"Create a TUV-x instance from a JSON/YAML configuration file");
|
|
32
50
|
|
|
33
51
|
tuvx.def(
|
|
34
52
|
"_delete_tuvx",
|
|
@@ -46,48 +64,109 @@ void bind_tuvx(py::module_& tuvx)
|
|
|
46
64
|
musica::TUVX* tuvx_instance = reinterpret_cast<musica::TUVX*>(tuvx_ptr);
|
|
47
65
|
|
|
48
66
|
// Get dimensions
|
|
49
|
-
int n_photolysis = tuvx_instance->
|
|
50
|
-
|
|
67
|
+
int n_photolysis = tuvx_instance->GetPhotolysisRateConstantCount();
|
|
51
68
|
int n_heating = tuvx_instance->GetHeatingRateCount();
|
|
52
|
-
|
|
69
|
+
int n_dose = tuvx_instance->GetDoseRateCount();
|
|
53
70
|
int n_layers = tuvx_instance->GetNumberOfLayers();
|
|
54
|
-
|
|
55
71
|
int n_sza_steps = tuvx_instance->GetNumberOfSzaSteps();
|
|
56
72
|
|
|
57
73
|
// Allocate output arrays (3D: sza_step, layer, reaction/heating_type)
|
|
58
74
|
std::vector<double> photolysis_rates(n_sza_steps * n_layers * n_photolysis);
|
|
59
75
|
std::vector<double> heating_rates(n_sza_steps * n_layers * n_heating);
|
|
76
|
+
std::vector<double> dose_rates(n_sza_steps * n_layers * n_dose);
|
|
60
77
|
|
|
61
78
|
// Run TUV-x (everything comes from the JSON config)
|
|
62
|
-
tuvx_instance->RunFromConfig(photolysis_rates.data(), heating_rates.data());
|
|
79
|
+
tuvx_instance->RunFromConfig(photolysis_rates.data(), heating_rates.data(), dose_rates.data());
|
|
63
80
|
|
|
64
81
|
// Return as numpy arrays with shape (n_sza_steps, n_layers, n_reactions/n_heating)
|
|
65
82
|
py::array_t<double> py_photolysis =
|
|
66
83
|
py::array_t<double>({ n_sza_steps, n_layers, n_photolysis }, photolysis_rates.data());
|
|
67
84
|
py::array_t<double> py_heating = py::array_t<double>({ n_sza_steps, n_layers, n_heating }, heating_rates.data());
|
|
85
|
+
py::array_t<double> py_dose = py::array_t<double>({ n_sza_steps, n_layers, n_dose }, dose_rates.data());
|
|
68
86
|
|
|
69
|
-
return py::make_tuple(py_photolysis, py_heating);
|
|
87
|
+
return py::make_tuple(py_photolysis, py_heating, py_dose);
|
|
70
88
|
},
|
|
71
89
|
"Run TUV-x (all parameters come from JSON config)",
|
|
72
90
|
py::arg("tuvx_instance"));
|
|
73
91
|
|
|
74
92
|
tuvx.def(
|
|
75
|
-
"
|
|
93
|
+
"_get_photolysis_rate_constants_ordering",
|
|
76
94
|
[](std::uintptr_t tuvx_ptr)
|
|
77
95
|
{
|
|
78
96
|
musica::TUVX* tuvx_instance = reinterpret_cast<musica::TUVX*>(tuvx_ptr);
|
|
79
97
|
|
|
80
|
-
|
|
98
|
+
musica::Error error;
|
|
99
|
+
musica::Mappings rate_map = tuvx_instance->GetPhotolysisRateConstantsOrdering(&error);
|
|
100
|
+
if (!musica::IsSuccess(error))
|
|
101
|
+
{
|
|
102
|
+
std::string error_message = std::string(error.message_.value_);
|
|
103
|
+
musica::DeleteError(&error);
|
|
104
|
+
throw py::value_error("Error getting photolysis rate constants ordering: " + error_message);
|
|
105
|
+
}
|
|
106
|
+
musica::DeleteError(&error);
|
|
107
|
+
|
|
108
|
+
py::dict rate_dict;
|
|
109
|
+
for (std::size_t i = 0; i < rate_map.size_; ++i)
|
|
110
|
+
{
|
|
111
|
+
py::str name(rate_map.mappings_[i].name_.value_);
|
|
112
|
+
std::size_t index = rate_map.mappings_[i].index_;
|
|
113
|
+
rate_dict[name] = index;
|
|
114
|
+
}
|
|
115
|
+
return rate_dict;
|
|
116
|
+
},
|
|
117
|
+
"Get photolysis rate names and their ordering in the output arrays");
|
|
118
|
+
|
|
119
|
+
tuvx.def(
|
|
120
|
+
"_get_heating_rates_ordering",
|
|
121
|
+
[](std::uintptr_t tuvx_ptr)
|
|
122
|
+
{
|
|
123
|
+
musica::TUVX* tuvx_instance = reinterpret_cast<musica::TUVX*>(tuvx_ptr);
|
|
124
|
+
|
|
125
|
+
musica::Error error;
|
|
126
|
+
musica::Mappings rate_map = tuvx_instance->GetHeatingRatesOrdering(&error);
|
|
127
|
+
if (!musica::IsSuccess(error))
|
|
128
|
+
{
|
|
129
|
+
std::string error_message = std::string(error.message_.value_);
|
|
130
|
+
musica::DeleteError(&error);
|
|
131
|
+
throw py::value_error("Error getting heating rates ordering: " + error_message);
|
|
132
|
+
}
|
|
133
|
+
musica::DeleteError(&error);
|
|
134
|
+
|
|
135
|
+
py::dict rate_dict;
|
|
136
|
+
for (std::size_t i = 0; i < rate_map.size_; ++i)
|
|
137
|
+
{
|
|
138
|
+
py::str name(rate_map.mappings_[i].name_.value_);
|
|
139
|
+
std::size_t index = rate_map.mappings_[i].index_;
|
|
140
|
+
rate_dict[name] = index;
|
|
141
|
+
}
|
|
142
|
+
return rate_dict;
|
|
81
143
|
},
|
|
82
|
-
"Get
|
|
144
|
+
"Get heating rate names and their ordering in the output arrays");
|
|
83
145
|
|
|
84
146
|
tuvx.def(
|
|
85
|
-
"
|
|
147
|
+
"_get_dose_rates_ordering",
|
|
86
148
|
[](std::uintptr_t tuvx_ptr)
|
|
87
149
|
{
|
|
88
150
|
musica::TUVX* tuvx_instance = reinterpret_cast<musica::TUVX*>(tuvx_ptr);
|
|
89
151
|
|
|
90
|
-
|
|
152
|
+
musica::Error error;
|
|
153
|
+
musica::Mappings rate_map = tuvx_instance->GetDoseRatesOrdering(&error);
|
|
154
|
+
if (!musica::IsSuccess(error))
|
|
155
|
+
{
|
|
156
|
+
std::string error_message = std::string(error.message_.value_);
|
|
157
|
+
musica::DeleteError(&error);
|
|
158
|
+
throw py::value_error("Error getting dose rates ordering: " + error_message);
|
|
159
|
+
}
|
|
160
|
+
musica::DeleteError(&error);
|
|
161
|
+
|
|
162
|
+
py::dict rate_dict;
|
|
163
|
+
for (std::size_t i = 0; i < rate_map.size_; ++i)
|
|
164
|
+
{
|
|
165
|
+
py::str name(rate_map.mappings_[i].name_.value_);
|
|
166
|
+
std::size_t index = rate_map.mappings_[i].index_;
|
|
167
|
+
rate_dict[name] = index;
|
|
168
|
+
}
|
|
169
|
+
return rate_dict;
|
|
91
170
|
},
|
|
92
|
-
"Get
|
|
171
|
+
"Get dose rate names and their ordering in the output arrays");
|
|
93
172
|
}
|
musica/tuvx.py
CHANGED
|
@@ -11,7 +11,7 @@ Note: TUV-x is only available on macOS and Linux platforms.
|
|
|
11
11
|
import os
|
|
12
12
|
import json
|
|
13
13
|
import tempfile
|
|
14
|
-
from typing import Dict, Tuple, List
|
|
14
|
+
from typing import Dict, Optional, Tuple, List
|
|
15
15
|
import numpy as np
|
|
16
16
|
from . import backend
|
|
17
17
|
|
|
@@ -19,40 +19,68 @@ _backend = backend.get_backend()
|
|
|
19
19
|
|
|
20
20
|
version = _backend._tuvx._get_tuvx_version() if backend.tuvx_available() else None
|
|
21
21
|
|
|
22
|
+
# Import the GridMap class from the backend
|
|
23
|
+
if backend.tuvx_available():
|
|
24
|
+
from .grid_map import GridMap
|
|
25
|
+
from .profile import Profile
|
|
26
|
+
from .profile_map import ProfileMap
|
|
27
|
+
else:
|
|
28
|
+
GridMap = None
|
|
29
|
+
Profile = None
|
|
30
|
+
ProfileMap = None
|
|
31
|
+
|
|
22
32
|
|
|
23
33
|
class TUVX:
|
|
24
34
|
"""
|
|
25
35
|
A Python interface to the TUV-x photolysis calculator.
|
|
26
36
|
|
|
27
|
-
This class provides a simplified interface that only requires a JSON configuration
|
|
28
|
-
|
|
29
|
-
earth-sun distance, atmospheric profiles, etc.) are specified in the JSON
|
|
37
|
+
This class provides a simplified interface that only requires a JSON/YAML configuration
|
|
38
|
+
to set up and run TUV-x calculations. All parameters (solar zenith angle,
|
|
39
|
+
earth-sun distance, atmospheric profiles, etc.) are specified in the JSON/YAML configuration.
|
|
40
|
+
|
|
41
|
+
The configuration can be in a file or provided as a string. Exactly one of `config_path` or
|
|
42
|
+
`config_string` must be provided.
|
|
30
43
|
"""
|
|
31
44
|
|
|
32
|
-
def __init__(self,
|
|
45
|
+
def __init__(self,
|
|
46
|
+
config_path: Optional[str] = None,
|
|
47
|
+
config_string: Optional[str] = None):
|
|
33
48
|
"""
|
|
34
49
|
Initialize a TUV-x instance from a configuration file.
|
|
35
50
|
|
|
36
51
|
Args:
|
|
37
52
|
config_path: Path to the JSON configuration file
|
|
53
|
+
config_string: JSON configuration as a string
|
|
38
54
|
|
|
39
55
|
Raises:
|
|
40
56
|
FileNotFoundError: If the configuration file doesn't exist
|
|
41
57
|
ValueError: If TUV-x initialization fails or TUVX is not available
|
|
42
58
|
"""
|
|
43
59
|
if not backend.tuvx_available():
|
|
44
|
-
raise ValueError("TUV-x backend is not available
|
|
60
|
+
raise ValueError("TUV-x backend is not available.")
|
|
45
61
|
|
|
46
|
-
if
|
|
62
|
+
if (config_path is None and config_string is None) or \
|
|
63
|
+
(config_path is not None and config_string is not None):
|
|
64
|
+
raise ValueError(
|
|
65
|
+
"Exactly one of config_path or config_string must be provided.")
|
|
66
|
+
|
|
67
|
+
if config_path is not None and not os.path.exists(config_path):
|
|
47
68
|
raise FileNotFoundError(
|
|
48
69
|
f"Configuration file not found: {config_path}")
|
|
49
70
|
|
|
50
|
-
|
|
51
|
-
|
|
71
|
+
if config_path is not None:
|
|
72
|
+
self._tuvx_instance = _backend._tuvx._create_tuvx_from_file(config_path)
|
|
73
|
+
self._config_path = config_path
|
|
74
|
+
self._config_string = None
|
|
75
|
+
elif config_string is not None:
|
|
76
|
+
self._tuvx_instance = _backend._tuvx._create_tuvx_from_string(config_string)
|
|
77
|
+
self._config_path = None
|
|
78
|
+
self._config_string = config_string
|
|
52
79
|
|
|
53
80
|
# Cache the names for efficiency
|
|
54
81
|
self._photolysis_names = None
|
|
55
82
|
self._heating_names = None
|
|
83
|
+
self._dose_names = None
|
|
56
84
|
|
|
57
85
|
def __del__(self):
|
|
58
86
|
"""Clean up the TUV-x instance."""
|
|
@@ -60,32 +88,45 @@ class TUVX:
|
|
|
60
88
|
_backend._tuvx._delete_tuvx(self._tuvx_instance)
|
|
61
89
|
|
|
62
90
|
@property
|
|
63
|
-
def photolysis_rate_names(self) ->
|
|
91
|
+
def photolysis_rate_names(self) -> dict[str, int]:
|
|
64
92
|
"""
|
|
65
93
|
Get the names of photolysis rates.
|
|
66
94
|
|
|
67
95
|
Returns:
|
|
68
|
-
|
|
96
|
+
Dictionary mapping photolysis rate names to their indices in the output arrays
|
|
69
97
|
"""
|
|
70
98
|
if self._photolysis_names is None:
|
|
71
|
-
self._photolysis_names = _backend._tuvx.
|
|
99
|
+
self._photolysis_names = _backend._tuvx._get_photolysis_rate_constants_ordering(
|
|
72
100
|
self._tuvx_instance)
|
|
73
101
|
return self._photolysis_names
|
|
74
102
|
|
|
75
103
|
@property
|
|
76
|
-
def heating_rate_names(self) ->
|
|
104
|
+
def heating_rate_names(self) -> dict[str, int]:
|
|
77
105
|
"""
|
|
78
106
|
Get the names of heating rates.
|
|
79
107
|
|
|
80
108
|
Returns:
|
|
81
|
-
|
|
109
|
+
Dictionary mapping heating rate names to their indices in the output arrays
|
|
82
110
|
"""
|
|
83
111
|
if self._heating_names is None:
|
|
84
|
-
self._heating_names = _backend._tuvx.
|
|
112
|
+
self._heating_names = _backend._tuvx._get_heating_rates_ordering(
|
|
85
113
|
self._tuvx_instance)
|
|
86
114
|
return self._heating_names
|
|
87
115
|
|
|
88
|
-
|
|
116
|
+
@property
|
|
117
|
+
def dose_rate_names(self) -> dict[str, int]:
|
|
118
|
+
"""
|
|
119
|
+
Get the names of dose rates.
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
Dictionary mapping dose rate names to their indices in the output arrays
|
|
123
|
+
"""
|
|
124
|
+
if self._dose_names is None:
|
|
125
|
+
self._dose_names = _backend._tuvx._get_dose_rates_ordering(
|
|
126
|
+
self._tuvx_instance)
|
|
127
|
+
return self._dose_names
|
|
128
|
+
|
|
129
|
+
def run(self) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
|
|
89
130
|
"""
|
|
90
131
|
Run the TUV-x photolysis calculator.
|
|
91
132
|
|
|
@@ -94,13 +135,14 @@ class TUVX:
|
|
|
94
135
|
|
|
95
136
|
Returns:
|
|
96
137
|
Tuple of (photolysis_rate_constants, heating_rates) as numpy arrays
|
|
97
|
-
- photolysis_rate_constants: Shape (n_layers, n_reactions) [s^-1]
|
|
98
|
-
- heating_rates: Shape (n_layers, n_heating_rates) [K s^-1]
|
|
138
|
+
- photolysis_rate_constants: Shape (n_sza, n_layers, n_reactions) [s^-1]
|
|
139
|
+
- heating_rates: Shape (n_sza, n_layers, n_heating_rates) [K s^-1]
|
|
140
|
+
- dose_rates: Shape (n_sza, n_layers, n_dose_rates) [W m^-2]
|
|
99
141
|
"""
|
|
100
|
-
photolysis_rates, heating_rates = _backend._tuvx._run_tuvx(
|
|
142
|
+
photolysis_rates, heating_rates, dose_rates = _backend._tuvx._run_tuvx(
|
|
101
143
|
self._tuvx_instance)
|
|
102
144
|
|
|
103
|
-
return photolysis_rates, heating_rates
|
|
145
|
+
return photolysis_rates, heating_rates, dose_rates
|
|
104
146
|
|
|
105
147
|
def get_photolysis_rate_constant(
|
|
106
148
|
self,
|
|
@@ -127,7 +169,7 @@ class TUVX:
|
|
|
127
169
|
f"Available reactions: {names}"
|
|
128
170
|
)
|
|
129
171
|
|
|
130
|
-
reaction_index = names
|
|
172
|
+
reaction_index = names[reaction_name]
|
|
131
173
|
return photolysis_rates[:, reaction_index]
|
|
132
174
|
|
|
133
175
|
def get_heating_rate(
|
|
@@ -155,9 +197,37 @@ class TUVX:
|
|
|
155
197
|
f"Available rates: {names}"
|
|
156
198
|
)
|
|
157
199
|
|
|
158
|
-
rate_index = names
|
|
200
|
+
rate_index = names[rate_name]
|
|
159
201
|
return heating_rates[:, rate_index]
|
|
160
202
|
|
|
203
|
+
def get_dose_rate(
|
|
204
|
+
self,
|
|
205
|
+
rate_name: str,
|
|
206
|
+
dose_rates: np.ndarray
|
|
207
|
+
) -> np.ndarray:
|
|
208
|
+
"""
|
|
209
|
+
Extract dose rates for a specific rate type.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
rate_name: Name of the dose rate
|
|
213
|
+
dose_rates: Output from run() method
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
1D array of dose rates for all layers [W m^-2]
|
|
217
|
+
|
|
218
|
+
Raises:
|
|
219
|
+
KeyError: If rate_name is not found
|
|
220
|
+
"""
|
|
221
|
+
names = self.dose_rate_names
|
|
222
|
+
if rate_name not in names:
|
|
223
|
+
raise KeyError(
|
|
224
|
+
f"Dose rate '{rate_name}' not found. "
|
|
225
|
+
f"Available rates: {names}"
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
rate_index = names[rate_name]
|
|
229
|
+
return dose_rates[:, rate_index]
|
|
230
|
+
|
|
161
231
|
@staticmethod
|
|
162
232
|
def create_config_from_dict(config_dict: Dict) -> 'TUVX':
|
|
163
233
|
"""
|
musica/types.py
CHANGED
|
@@ -8,6 +8,7 @@ from .constants import GAS_CONSTANT
|
|
|
8
8
|
from typing import Optional, Dict, List, Union, Tuple, TYPE_CHECKING, Any
|
|
9
9
|
from os import PathLike
|
|
10
10
|
import math
|
|
11
|
+
import numpy as np
|
|
11
12
|
|
|
12
13
|
# Import backend symbols from the backend module
|
|
13
14
|
from . import backend
|
|
@@ -35,6 +36,13 @@ else:
|
|
|
35
36
|
FilePath = Union[str, "PathLike[str]"]
|
|
36
37
|
|
|
37
38
|
|
|
39
|
+
def is_scalar_number(x):
|
|
40
|
+
return (
|
|
41
|
+
isinstance(x, (int, float, np.number))
|
|
42
|
+
and not isinstance(x, bool)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
|
|
38
46
|
class Conditions(_Conditions):
|
|
39
47
|
"""
|
|
40
48
|
Conditions class for the MICM solver. If air density is not provided,
|
|
@@ -119,7 +127,7 @@ class State():
|
|
|
119
127
|
if name not in self.__species_ordering:
|
|
120
128
|
raise ValueError(f"Species {name} not found in the mechanism.")
|
|
121
129
|
i_species = self.__species_ordering[name]
|
|
122
|
-
if
|
|
130
|
+
if is_scalar_number(value):
|
|
123
131
|
value = [value]
|
|
124
132
|
if len(value) != self.__number_of_grid_cells:
|
|
125
133
|
raise ValueError(
|
|
@@ -150,7 +158,7 @@ class State():
|
|
|
150
158
|
raise ValueError(
|
|
151
159
|
f"User-defined rate parameter {name} not found in the mechanism.")
|
|
152
160
|
i_param = self.__user_defined_rate_parameters_ordering[name]
|
|
153
|
-
if
|
|
161
|
+
if is_scalar_number(value):
|
|
154
162
|
value = [value]
|
|
155
163
|
if len(value) != self.__number_of_grid_cells:
|
|
156
164
|
raise ValueError(
|
|
@@ -184,17 +192,17 @@ class State():
|
|
|
184
192
|
air_densities : Optional[Union[float, List[float]]]
|
|
185
193
|
Air density in mol m-3. If not provided, it will be calculated from the Ideal Gas Law.
|
|
186
194
|
"""
|
|
187
|
-
if temperatures is not None and (
|
|
195
|
+
if temperatures is not None and is_scalar_number(temperatures):
|
|
188
196
|
if self.__number_of_grid_cells > 1:
|
|
189
197
|
raise ValueError(
|
|
190
198
|
f"temperatures must be a list of length {self.__number_of_grid_cells}.")
|
|
191
199
|
temperatures = [temperatures]
|
|
192
|
-
if pressures is not None and (
|
|
200
|
+
if pressures is not None and is_scalar_number(pressures):
|
|
193
201
|
if self.__number_of_grid_cells > 1:
|
|
194
202
|
raise ValueError(
|
|
195
203
|
f"pressures must be a list of length {self.__number_of_grid_cells}.")
|
|
196
204
|
pressures = [pressures]
|
|
197
|
-
if air_densities is not None and (
|
|
205
|
+
if air_densities is not None and is_scalar_number(air_densities):
|
|
198
206
|
if self.__number_of_grid_cells > 1:
|
|
199
207
|
raise ValueError(
|
|
200
208
|
f"air_densities must be a list of length {self.__number_of_grid_cells}.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: musica
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.13.0
|
|
4
4
|
Summary: MUSICA is a Python library for performing computational simulations in atmospheric chemistry.
|
|
5
5
|
Author-Email: Matthew Dawsom <mattdawson@ucar.edu>, Jiwon Gim <jiwongim@ucar.edu>, David Fillmore <fillmore@ucar.edu>, Kyle Shores <kshores@ucar.edu>, Montek Thind <mthind@ucar.edu>
|
|
6
6
|
Maintainer-Email: ACOM MUSICA Developers <musica-support@ucar.edu>
|
|
@@ -208,24 +208,24 @@ License: Apache License
|
|
|
208
208
|
|
|
209
209
|
Project-URL: homepage, https://wiki.ucar.edu/display/MUSICA/MUSICA+Home
|
|
210
210
|
Requires-Python: >=3.9
|
|
211
|
+
Requires-Dist: numpy>=2.0.0
|
|
211
212
|
Requires-Dist: pyyaml>=6.0.2
|
|
212
|
-
Requires-Dist: xarray>=2022.3.0
|
|
213
213
|
Requires-Dist: ussa1976>=v0.3.4
|
|
214
|
+
Requires-Dist: xarray>=2022.3.0
|
|
214
215
|
Provides-Extra: test
|
|
215
|
-
Requires-Dist:
|
|
216
|
-
Requires-Dist:
|
|
217
|
-
Requires-Dist: matplotlib; extra == "test"
|
|
216
|
+
Requires-Dist: pytest>=7.0.0; extra == "test"
|
|
217
|
+
Requires-Dist: matplotlib>=3.6.0; extra == "test"
|
|
218
218
|
Provides-Extra: gpu
|
|
219
|
-
Requires-Dist: nvidia-cublas-cu12; extra == "gpu"
|
|
220
|
-
Requires-Dist: nvidia-cuda-runtime-cu12; extra == "gpu"
|
|
219
|
+
Requires-Dist: nvidia-cublas-cu12>=12.6.4.1; extra == "gpu"
|
|
220
|
+
Requires-Dist: nvidia-cuda-runtime-cu12>=12.6.68; extra == "gpu"
|
|
221
221
|
Provides-Extra: tutorial
|
|
222
|
-
Requires-Dist:
|
|
223
|
-
Requires-Dist:
|
|
224
|
-
Requires-Dist:
|
|
225
|
-
Requires-Dist:
|
|
226
|
-
Requires-Dist:
|
|
227
|
-
Requires-Dist:
|
|
228
|
-
Requires-Dist:
|
|
222
|
+
Requires-Dist: dask-jobqueue>=0.8.0; extra == "tutorial"
|
|
223
|
+
Requires-Dist: dask[distributed]>=2022.3.0; extra == "tutorial"
|
|
224
|
+
Requires-Dist: matplotlib>=3.6.0; extra == "tutorial"
|
|
225
|
+
Requires-Dist: numpy>=2.0.0; extra == "tutorial"
|
|
226
|
+
Requires-Dist: pandas>=2.2.0; extra == "tutorial"
|
|
227
|
+
Requires-Dist: scipy>=1.10.0; extra == "tutorial"
|
|
228
|
+
Requires-Dist: seaborn>=0.12.0; extra == "tutorial"
|
|
229
229
|
Description-Content-Type: text/markdown
|
|
230
230
|
|
|
231
231
|
# MUSICA
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
musica-0.13.0.dist-info/RECORD,,
|
|
2
|
+
musica-0.13.0.dist-info/WHEEL,sha256=qdO6WnDiDW9GigE7BL6ZZjKOjAgb6iacSCh606yDCxw,139
|
|
3
|
+
musica-0.13.0.dist-info/entry_points.txt,sha256=t9qRU9Ya63_yYMKJkTiVS5kCaW6dDDr0wuQ26lgXTH8,49
|
|
4
|
+
musica-0.13.0.dist-info/METADATA,sha256=TH2C-ia8-RRs9ea99MPrN5uk24JBz85UisjjvgjfccY,26422
|
|
5
|
+
musica-0.13.0.dist-info/licenses/AUTHORS.md,sha256=CYIlKZmXT9ngFk6d0MiD0A_Pt8BFoID4n-29OMrKkbM,2632
|
|
6
|
+
musica-0.13.0.dist-info/licenses/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
7
|
+
musica/grid.py,sha256=Gl8pD7jdD1WKquEaxPoUhngXKkqj0HoTbel9IFAk_-k,3489
|
|
8
|
+
musica/backend.py,sha256=Ed0vqpdem4a4sz5XOPiBdi1TPQy80qVDcmZUqI5lZvw,1040
|
|
9
|
+
musica/CMakeLists.txt,sha256=jSV0QLWVBacLSPZt6a_KL85Pf9cImIwPk1YfMTYBHGo,1815
|
|
10
|
+
musica/grid_map.cpp,sha256=ubfKALauWZdcA_o6_bQ_Ox3f8OK5zr1QmGNnUz9Hzd8,4132
|
|
11
|
+
musica/_version.py,sha256=GUSloiYVJdj7bMD9lC6vxo5gID8BFxzSPteJ-Fdni1c,19
|
|
12
|
+
musica/profile.py,sha256=8cbg1ais2J40AvqMK3OzdZEXHH3_2BHmH277_Vsvtvw,3619
|
|
13
|
+
musica/constants.py,sha256=RsZrtjy8vlIcQxV9F9xzlSYFeGBQBHmhFWDPB7pRQH8,123
|
|
14
|
+
musica/binding_common.cpp,sha256=lBL02ssrTPIxOb9bTRjKQdz0b6HVWbAbXNFgeM1ht5s,962
|
|
15
|
+
musica/__init__.py,sha256=2xoebKVljHzrzupxtAbK3Wg05p38Lq0SFIbDjR0--bs,392
|
|
16
|
+
musica/profile.cpp,sha256=UrywN_oX7C_Ma7iTOg9-wQzPSZZcpwnqb89XWOJWkz8,12482
|
|
17
|
+
musica/tuvx.py,sha256=LBIikwFFvG_38wJ27nMRUJPXp9NMX89kdc23u0MWIGE,8915
|
|
18
|
+
musica/cpu_binding.cpp,sha256=AZXO6EpL5HofGJ1s11fprrXYVG2U1ZrdUxe3M9j5kpw,225
|
|
19
|
+
musica/types.py,sha256=KqIiFDH8_siO8rcg8lgaK5hpPi7Aa8RkN4dWt4ZqZ24,17125
|
|
20
|
+
musica/gpu_binding.cpp,sha256=y9Fzgn9unoGz_Fqqlk_NBWy4jHOwTv8E82e3bq_phMg,229
|
|
21
|
+
musica/tuvx.cpp,sha256=KFUihqAdc3pR1ubUzf-SeVsawYrytPfTQgguRM-vzqc,6243
|
|
22
|
+
musica/_musica.cpython-39-darwin.so,sha256=S_i8McjwujD3bZVoEsbH19lLfZHaOdqjrcpPhh1QVQ4,3947952
|
|
23
|
+
musica/cuda.py,sha256=rtMNdmixfEsy5J4pfKOc6LfBuFECxCKsi8J0jAvtyHo,258
|
|
24
|
+
musica/cuda.cpp,sha256=qQOLKTUOB83gE-963rT579Me-NrqMUWnXDKmpTPMVFg,346
|
|
25
|
+
musica/binding_common.hpp,sha256=UHkJDBl3wdbLJn51jspU0EAq-kqRAQ3GYSAkTmcCl5A,549
|
|
26
|
+
musica/grid.cpp,sha256=EyUe9sXzdZClodU0eC--Hw3kFU-uFXj1Vi1VDxL9VDE,8564
|
|
27
|
+
musica/grid_map.py,sha256=lmalFY2bLj4aVZ2YiJpgVs0iTSAyt5VHooqIgK2iiQg,5227
|
|
28
|
+
musica/mechanism_configuration.cpp,sha256=1Wcettuy1dzujVmbmICbBiAxfKl49RBMu5jZ-PW7WE4,22430
|
|
29
|
+
musica/profile_map.py,sha256=t-KwmmW37kiC9AzYvyPIoq7io9zURDbdweNG-TEP5UY,5506
|
|
30
|
+
musica/profile_map.cpp,sha256=lR2rriQrZhsOfLxozTClAGP-50-lsmqo9f0GYINtvjw,4263
|
|
31
|
+
musica/carma.py,sha256=fmM3K0Rm1hl2l8vGM9mIi0aKgnMhT0xsU3Xo2sP43Ug,66987
|
|
32
|
+
musica/main.py,sha256=-TOa-WvGKY1aPewQ2WtzFV3myoEQI6-MYoQt2Hw5GXc,2708
|
|
33
|
+
musica/carma.cpp,sha256=K3LxfhzetHeZikSZ_mg1YchmCJ8Sr7eoo55Lu6MBqts,42334
|
|
34
|
+
musica/musica.cpp,sha256=T0LuAJnzaSE3VxBygautNOWnBT62gSF3Nl1NFT29-BI,8222
|
|
35
|
+
musica/tools/prepare_build_environment_macos.sh,sha256=Yhhd-8W6YvR79NabEqixexU6BsClNf7DH_EYYlsmeMo,41
|
|
36
|
+
musica/tools/prepare_build_environment_linux.sh,sha256=zqpqoI3hFYftBfj2MTpHz2Gg3TGVhcJ1U2z7IauSPug,986
|
|
37
|
+
musica/tools/repair_wheel_gpu.sh,sha256=GJcKUJ2n9KMsj3QC5Shxt_ks9uFu2f9Than-4vVhG9U,1485
|
|
38
|
+
musica/test/unit/test_parser.py,sha256=-dWfwiaGiyNrWbBC_HW0ws8bhhHhM8b-qfW0v3e7bZU,2314
|
|
39
|
+
musica/test/unit/test_grid.py,sha256=ZI64kushvZzA1YonGqiu6dAX-fIkSGs_iWWRqJdrlF0,4465
|
|
40
|
+
musica/test/unit/test_serializer.py,sha256=AuOl_5nhbowq_HGsy1hoRJpyOW60frS2fyb-o0PsQvA,2128
|
|
41
|
+
musica/test/unit/test_profile.py,sha256=eARs7XGFgM_EsQYVEP7oK0fqAeEsM4lGjwMkLMIG_Zk,6534
|
|
42
|
+
musica/test/unit/test_util_full_mechanism.py,sha256=izP631HB2j8U0JMHtd0A1zMI7GpA9sdcalf0Y1XIKkY,16353
|
|
43
|
+
musica/test/unit/test_state.py,sha256=xjIn4uwLLm7NdgFBnMhUGL9HqTWtADn8gOVNVzIs6ck,10872
|
|
44
|
+
musica/test/unit/test_profile_map.py,sha256=-tfY8c96EAws1WhYCAi_WFwCDd6Ml00zk_tctOKc0P0,4556
|
|
45
|
+
musica/test/unit/test_grid_map.py,sha256=JlNhwuHi8PxsgIeGtZh5MTqTyz2vD7pSO5QCMQY-5W8,3520
|
|
46
|
+
musica/test/integration/test_chapman.py,sha256=AQGyzh8ESiJk-jj0Vx1eUTv3OtK0vbI4DLkZI6rfx1I,3482
|
|
47
|
+
musica/test/integration/test_sulfate_box_model.py,sha256=Ww6rI8_f4vgiYZ2_pt6hFu13abNaOm8i1TocISYET_s,1604
|
|
48
|
+
musica/test/integration/test_carma_aluminum.py,sha256=B4xpfYEQxQIeUe5TcAXdtS4s1yD9cd6dQFZSUXY8ZLM,356
|
|
49
|
+
musica/test/integration/test_carma_sulfate.py,sha256=6SWcRjKY96uJhk4ifqiwTjFmH396j3i4bUfKXoJMtNI,742
|
|
50
|
+
musica/test/integration/test_tuvx.py,sha256=DuTCQ0l8krlIU95FtHvFJ6s4MsNwEYx7bxjYkYBdiUA,5629
|
|
51
|
+
musica/test/integration/test_carma.py,sha256=iR6FnhSfG6seta4K-C9IPtYdia9GlH8DzyVyP3w07zc,6865
|
|
52
|
+
musica/test/integration/test_analytical.py,sha256=3P9pw7mRnXi7oXn_2vdEZSBFc4U5m0eRJgKEvX3esZ8,13805
|
|
53
|
+
musica/test/examples/v1/full_configuration/full_configuration.yaml,sha256=3JmeA5457k78ZLQLHE2OC9gsNXUTMC-ZYMYasYmRRkg,3952
|
|
54
|
+
musica/test/examples/v1/full_configuration/full_configuration.json,sha256=jEMW84FjWI2rdqfAA7S7KSWSeTiJQw-1GCdDrFwRiRM,6149
|
|
55
|
+
musica/.dylibs/libhdf5.310.5.1.dylib,sha256=83ZEgjgvsW-33kHKGygxRBjKqJd1WretY1xMvGMHCIU,3277072
|
|
56
|
+
musica/.dylibs/libaec.0.1.4.dylib,sha256=_C-rTFuk7CkvfqzOFQrY4CqNXfhtaQ0ckGkUYP_F6ew,70928
|
|
57
|
+
musica/.dylibs/libnetcdf.22.dylib,sha256=f5kk7mMIK1ia2Ac8IiKAkXQbq6V2g_5Em7Kkgg_m10Y,1309456
|
|
58
|
+
musica/.dylibs/libgfortran.5.dylib,sha256=8ZjiwRSk2dI5q9jZPVlLtfC1bjuK3BittDQFZdSBZ_Y,2161472
|
|
59
|
+
musica/.dylibs/libsz.2.0.1.dylib,sha256=jkXYTFpNzAsfqN64UMAJVGZfThfQ_rNkzku2cS3xTIg,71344
|
|
60
|
+
musica/.dylibs/libhdf5_hl.310.0.6.dylib,sha256=spwH6SJg-kdpEEdrlii-NH_T7hCYy7yv2Kgbaxiec3Q,155824
|
|
61
|
+
musica/.dylibs/libquadmath.0.dylib,sha256=61M_AHSknldrC3N-YdjkurQ1zU_9gYIccIrQPy9Ua_s,362768
|
|
62
|
+
musica/.dylibs/libgcc_s.1.1.dylib,sha256=RROUGdpfPwsbOtunOwCfguzhxRSP0SlmF2FMERjgFBU,220288
|
|
63
|
+
musica/.dylibs/libnetcdff.7.1.0.dylib,sha256=9HqSrG2wkwdrs-0-4N_5wrVOfaQ89GGbH4iT-4iBTyw,894768
|
|
64
|
+
musica/.dylibs/libzstd.1.5.7.dylib,sha256=MQGj484yvsxhgqlQFGJtjbuBR0MOBVImXwujJ7rO0Hk,654000
|
|
65
|
+
musica/mechanism_configuration/phase.py,sha256=_u55lBuBiJzXAhwmqzkjFB1LcjWdvficzRK6QDKfynA,1905
|
|
66
|
+
musica/mechanism_configuration/species.py,sha256=5Y-4UfCOHRss-pgWW9i0VsV5fKnJ6qYSTFLduhjjYOQ,2899
|
|
67
|
+
musica/mechanism_configuration/tunneling.py,sha256=CbaoW_jarD0asMzi0ZB6fWpD64Pz9pZ9YVFWkUtmm8A,4313
|
|
68
|
+
musica/mechanism_configuration/taylor_series.py,sha256=Ir8EpMsSIRF4gcdIcudBJKgkCuuVOvio5EQpks-meP8,5397
|
|
69
|
+
musica/mechanism_configuration/phase_species.py,sha256=OHb8kpjliSE6ROQgKOtd9Er4SW20vFYJKpstJTrfdTY,2225
|
|
70
|
+
musica/mechanism_configuration/branched.py,sha256=3_Z_LdkCkf4jTePECNx0w7ZiNF9-Q2l6zA5owe2aPs4,5244
|
|
71
|
+
musica/mechanism_configuration/reactions.py,sha256=rk90j-Q2R-wl6UDYKc-u9Bv4Fv2hJCULoPXdH6_GPr4,744
|
|
72
|
+
musica/mechanism_configuration/__init__.py,sha256=kX2xE_xxdTuLJXfzJRrQHC4fHuoXDmATArwdYf5RzfI,668
|
|
73
|
+
musica/mechanism_configuration/user_defined.py,sha256=lxG1t2Exab-kPnKkUWWBBNMJqZplT6-D67_ErvHCNlY,3669
|
|
74
|
+
musica/mechanism_configuration/reaction_component.py,sha256=OugCa_q4aA_zTMCi1Ymfk6tOpgjhrYfisGfsGpBNtpQ,2002
|
|
75
|
+
musica/mechanism_configuration/mechanism.py,sha256=E-H_bNI0wopKScyU01jNy5BB8NMSZ5SWAqn4x3CUQ7k,2976
|
|
76
|
+
musica/mechanism_configuration/first_order_loss.py,sha256=NET7HTjUgQfrg3Ijh5dxDffkgQIEZKTUMTfmPY48z3g,3280
|
|
77
|
+
musica/mechanism_configuration/utils.py,sha256=nR-ukwYsplFfnsjXtKQsXnryMPvtjkZkFQv7TjcSrnE,346
|
|
78
|
+
musica/mechanism_configuration/ancillary.py,sha256=wavdS74AirouENvx8oxDMjr7_f3WWMH08vtaCHShgpQ,224
|
|
79
|
+
musica/mechanism_configuration/arrhenius.py,sha256=kGjCFWsoHU6R3nqsRXl47gES5RH-iPUmjO4AtH_ESS0,5261
|
|
80
|
+
musica/mechanism_configuration/troe.py,sha256=ndHbX-I5BAG54RNBWOKeJChneBv7dQyiQ8MKW0xBckA,6393
|
|
81
|
+
musica/mechanism_configuration/photolysis.py,sha256=o6uyj3y9zXx3uQFftMY97MUA5yi-_jqXnESPdLmTBmc,3581
|
|
82
|
+
musica/mechanism_configuration/emission.py,sha256=Bik-_c3W_im6Zqu22CRgILp2EdyITYTiMe6oDfWxyhk,2902
|
|
83
|
+
musica/mechanism_configuration/surface.py,sha256=uVUkSnZ4EbQKrYHHpBCfVeJTdaYXFjvvJCGOYmp_UE8,3726
|
|
84
|
+
musica/mechanism_configuration/ternary_chemical_activation.py,sha256=YZEXgKF29yMzWTWbNc-3Aa6laWuzG8fi2DmUsJ6fxPk,6906
|
|
85
|
+
musica/examples/__init__.py,sha256=A4k3hoNAvcGzHlzJZ9yuy9H2n1jTSJzB6LsS7veUa_w,31
|
|
86
|
+
musica/examples/carma_sulfate.py,sha256=Jmm8CLyBtNDK06Hb94jsnR-hVGxZNES3HNxrIrHIW84,8119
|
|
87
|
+
musica/examples/sulfate_box_model.py,sha256=cf0-_Z8rrTSxFrFPjIwYDYZcwNdiiYnk6IZ2zPH1cTo,16671
|
|
88
|
+
musica/examples/examples.py,sha256=087VoazqnByZSjMEb_Vo1KoUNOO0xRw_fQ9XY7eitNc,5736
|
|
89
|
+
musica/examples/ts1_latin_hypercube.py,sha256=v6FhWxVQSZJvj55XblsIGVdq4f7CucttxDKjVlz6k1A,9623
|
|
90
|
+
musica/examples/carma_aluminum.py,sha256=tYji_Gna2VoKVFxzNOymeIqRzLvGo0PRefeyqaK0N-k,3684
|