musica 0.12.1__cp39-cp39-win_amd64.whl → 0.13.0__cp39-cp39-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.

Potentially problematic release.


This version of musica might be problematic. Click here for more details.

Files changed (72) hide show
  1. musica/CMakeLists.txt +4 -0
  2. musica/_musica.cp39-win_amd64.pyd +0 -0
  3. musica/_version.py +1 -1
  4. musica/binding_common.cpp +6 -9
  5. musica/binding_common.hpp +17 -1
  6. musica/examples/__init__.py +1 -1
  7. musica/examples/carma_aluminum.py +1 -0
  8. musica/examples/carma_sulfate.py +1 -0
  9. musica/examples/sulfate_box_model.py +2 -2
  10. musica/examples/ts1_latin_hypercube.py +1 -1
  11. musica/grid.cpp +206 -0
  12. musica/grid.py +98 -0
  13. musica/grid_map.cpp +117 -0
  14. musica/grid_map.py +167 -0
  15. musica/mechanism_configuration/__init__.py +18 -1
  16. musica/mechanism_configuration/ancillary.py +6 -0
  17. musica/mechanism_configuration/arrhenius.py +111 -269
  18. musica/mechanism_configuration/branched.py +116 -275
  19. musica/mechanism_configuration/emission.py +63 -52
  20. musica/mechanism_configuration/first_order_loss.py +73 -157
  21. musica/mechanism_configuration/mechanism.py +93 -0
  22. musica/mechanism_configuration/phase.py +44 -33
  23. musica/mechanism_configuration/phase_species.py +58 -0
  24. musica/mechanism_configuration/photolysis.py +77 -67
  25. musica/mechanism_configuration/reaction_component.py +54 -0
  26. musica/mechanism_configuration/reactions.py +17 -58
  27. musica/mechanism_configuration/species.py +45 -71
  28. musica/mechanism_configuration/surface.py +78 -74
  29. musica/mechanism_configuration/taylor_series.py +136 -0
  30. musica/mechanism_configuration/ternary_chemical_activation.py +138 -330
  31. musica/mechanism_configuration/troe.py +138 -330
  32. musica/mechanism_configuration/tunneling.py +105 -229
  33. musica/mechanism_configuration/user_defined.py +79 -68
  34. musica/mechanism_configuration.cpp +54 -162
  35. musica/musica.cpp +2 -5
  36. musica/profile.cpp +294 -0
  37. musica/profile.py +93 -0
  38. musica/profile_map.cpp +117 -0
  39. musica/profile_map.py +167 -0
  40. musica/test/examples/v1/full_configuration/full_configuration.json +91 -233
  41. musica/test/examples/v1/full_configuration/full_configuration.yaml +191 -290
  42. musica/test/integration/test_carma_aluminum.py +2 -1
  43. musica/test/integration/test_carma_sulfate.py +2 -1
  44. musica/test/integration/test_chapman.py +2 -2
  45. musica/test/integration/test_sulfate_box_model.py +1 -1
  46. musica/test/integration/test_tuvx.py +72 -15
  47. musica/test/unit/test_grid.py +137 -0
  48. musica/test/unit/test_grid_map.py +126 -0
  49. musica/test/unit/test_parser.py +10 -10
  50. musica/test/unit/test_profile.py +169 -0
  51. musica/test/unit/test_profile_map.py +137 -0
  52. musica/test/unit/test_serializer.py +17 -16
  53. musica/test/unit/test_state.py +338 -0
  54. musica/test/unit/test_util_full_mechanism.py +78 -298
  55. musica/tools/prepare_build_environment_linux.sh +7 -25
  56. musica/tuvx.cpp +94 -15
  57. musica/tuvx.py +92 -22
  58. musica/types.py +28 -17
  59. {musica-0.12.1.dist-info → musica-0.13.0.dist-info}/METADATA +15 -14
  60. musica-0.13.0.dist-info/RECORD +80 -0
  61. {musica-0.12.1.dist-info → musica-0.13.0.dist-info}/WHEEL +1 -1
  62. musica/mechanism_configuration/aqueous_equilibrium.py +0 -274
  63. musica/mechanism_configuration/condensed_phase_arrhenius.py +0 -309
  64. musica/mechanism_configuration/condensed_phase_photolysis.py +0 -88
  65. musica/mechanism_configuration/henrys_law.py +0 -44
  66. musica/mechanism_configuration/mechanism_configuration.py +0 -234
  67. musica/mechanism_configuration/simpol_phase_transfer.py +0 -217
  68. musica/mechanism_configuration/wet_deposition.py +0 -52
  69. musica-0.12.1.dist-info/RECORD +0 -69
  70. {musica-0.12.1.dist-info → musica-0.13.0.dist-info}/entry_points.txt +0 -0
  71. {musica-0.12.1.dist-info → musica-0.13.0.dist-info}/licenses/AUTHORS.md +0 -0
  72. {musica-0.12.1.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
- "_create_tuvx",
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->CreateFromConfigOnly(config_path);
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->GetPhotolysisRateCount();
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
- "_get_photolysis_rate_names",
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
- return tuvx_instance->GetPhotolysisRateNames();
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 photolysis rate names");
144
+ "Get heating rate names and their ordering in the output arrays");
83
145
 
84
146
  tuvx.def(
85
- "_get_heating_rate_names",
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
- return tuvx_instance->GetHeatingRateNames();
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 heating rate names");
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
- file to set up and run TUV-x calculations. All parameters (solar zenith angle,
29
- earth-sun distance, atmospheric profiles, etc.) are specified in the JSON config.
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, config_path: str):
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 on windows.")
60
+ raise ValueError("TUV-x backend is not available.")
45
61
 
46
- if not os.path.exists(config_path):
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
- self._tuvx_instance = _backend._tuvx._create_tuvx(config_path)
51
- self._config_path = config_path
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) -> List[str]:
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
- List of photolysis rate names
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._get_photolysis_rate_names(
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) -> List[str]:
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
- List of heating rate names
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._get_heating_rate_names(
112
+ self._heating_names = _backend._tuvx._get_heating_rates_ordering(
85
113
  self._tuvx_instance)
86
114
  return self._heating_names
87
115
 
88
- def run(self) -> Tuple[np.ndarray, np.ndarray]:
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.index(reaction_name)
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.index(rate_name)
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 isinstance(value, float) or isinstance(value, int):
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 isinstance(value, float) or isinstance(value, int):
161
+ if is_scalar_number(value):
154
162
  value = [value]
155
163
  if len(value) != self.__number_of_grid_cells:
156
164
  raise ValueError(
@@ -165,43 +173,44 @@ class State():
165
173
  k += 1
166
174
 
167
175
  def set_conditions(self,
168
- temperatures: Union[Union[float, int], List[Union[float, int]]],
169
- pressures: Union[Union[float, int], List[Union[float, int]]],
176
+ temperatures: Optional[Union[Union[float, int], List[Union[float, int]]]] = None,
177
+ pressures: Optional[Union[Union[float, int], List[Union[float, int]]]] = None,
170
178
  air_densities: Optional[Union[Union[float, int], List[Union[float, int]]]] = None):
171
179
  """
172
180
  Set the conditions for the state. The individual conditions can be a single value
173
181
  when solving for a single grid cell, or a list of values when solving for multiple grid cells.
174
182
  If air density is not provided, it will be calculated from the Ideal Gas Law using the provided
175
- temperature and pressure.
183
+ temperature and pressure. If temperature or pressure are not provided, their values will remain
184
+ unchanged.
176
185
 
177
186
  Parameters
178
187
  ----------
179
- temperatures : Union[float, List[float]]
188
+ temperatures : Optional[Union[float, List[float]]]
180
189
  Temperature in Kelvin.
181
- pressures : Union[float, List[float]]
190
+ pressures : Optional[Union[float, List[float]]]
182
191
  Pressure in Pascals.
183
192
  air_densities : Optional[Union[float, List[float]]]
184
193
  Air density in mol m-3. If not provided, it will be calculated from the Ideal Gas Law.
185
194
  """
186
- if isinstance(temperatures, float) or isinstance(temperatures, int):
195
+ if temperatures is not None and is_scalar_number(temperatures):
187
196
  if self.__number_of_grid_cells > 1:
188
197
  raise ValueError(
189
198
  f"temperatures must be a list of length {self.__number_of_grid_cells}.")
190
199
  temperatures = [temperatures]
191
- if isinstance(pressures, float) or isinstance(pressures, int):
200
+ if pressures is not None and is_scalar_number(pressures):
192
201
  if self.__number_of_grid_cells > 1:
193
202
  raise ValueError(
194
203
  f"pressures must be a list of length {self.__number_of_grid_cells}.")
195
204
  pressures = [pressures]
196
- if air_densities is not None and (isinstance(air_densities, float) or isinstance(air_densities, int)):
205
+ if air_densities is not None and is_scalar_number(air_densities):
197
206
  if self.__number_of_grid_cells > 1:
198
207
  raise ValueError(
199
208
  f"air_densities must be a list of length {self.__number_of_grid_cells}.")
200
209
  air_densities = [air_densities]
201
- if len(temperatures) != self.__number_of_grid_cells:
210
+ if temperatures is not None and len(temperatures) != self.__number_of_grid_cells:
202
211
  raise ValueError(
203
212
  f"temperatures must be a list of length {self.__number_of_grid_cells}.")
204
- if len(pressures) != self.__number_of_grid_cells:
213
+ if pressures is not None and len(pressures) != self.__number_of_grid_cells:
205
214
  raise ValueError(
206
215
  f"pressures must be a list of length {self.__number_of_grid_cells}.")
207
216
  if air_densities is not None and len(air_densities) != self.__number_of_grid_cells:
@@ -210,10 +219,10 @@ class State():
210
219
  k = 0
211
220
  for state in self.__states:
212
221
  for condition in state.conditions:
213
- condition.temperature = temperatures[k]
214
- condition.pressure = pressures[k]
215
- condition.air_density = air_densities[k] if air_densities is not None else pressures[k] / (
216
- GAS_CONSTANT * temperatures[k])
222
+ condition.temperature = temperatures[k] if temperatures is not None else condition.temperature
223
+ condition.pressure = pressures[k] if pressures is not None else condition.pressure
224
+ condition.air_density = air_densities[k] if air_densities is not None else condition.pressure / (
225
+ GAS_CONSTANT * condition.temperature)
217
226
  k += 1
218
227
 
219
228
  def get_concentrations(self) -> Dict[str, List[float]]:
@@ -334,11 +343,13 @@ class MICM():
334
343
  Mechanism object which specifies the chemical mechanism to use. If provided, this will be used
335
344
  to create the solver.
336
345
  solver_type : SolverType, optional
337
- Type of solver to use. If not provided, the default solver type will be used.
346
+ Type of solver to use. If not provided, the default Rosenbrock (with standard-ordered matrices) solver type will be used.
338
347
  ignore_non_gas_phases : bool, optional
339
348
  If True, non-gas phases will be ignored when configuring micm with the mechanism. This is only needed
340
349
  until micm properly supports non-gas phases. This option is only supported when passing in a mechanism.
341
350
  """
351
+ if solver_type is None:
352
+ solver_type = SolverType.rosenbrock_standard_order
342
353
  self.__solver_type = solver_type
343
354
  self.__vector_size = _vector_size(solver_type)
344
355
  if config_path is None and mechanism is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: musica
3
- Version: 0.12.1
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>
@@ -207,24 +207,25 @@ License: Apache License
207
207
  limitations under the License.
208
208
 
209
209
  Project-URL: homepage, https://wiki.ucar.edu/display/MUSICA/MUSICA+Home
210
+ Requires-Python: >=3.9
211
+ Requires-Dist: numpy>=2.0.0
210
212
  Requires-Dist: pyyaml>=6.0.2
211
- Requires-Dist: xarray>=2022.3.0
212
213
  Requires-Dist: ussa1976>=v0.3.4
214
+ Requires-Dist: xarray>=2022.3.0
213
215
  Provides-Extra: test
214
- Requires-Dist: numpy; extra == "test"
215
- Requires-Dist: pytest; extra == "test"
216
- Requires-Dist: matplotlib; extra == "test"
216
+ Requires-Dist: pytest>=7.0.0; extra == "test"
217
+ Requires-Dist: matplotlib>=3.6.0; extra == "test"
217
218
  Provides-Extra: gpu
218
- Requires-Dist: nvidia-cublas-cu12; extra == "gpu"
219
- 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"
220
221
  Provides-Extra: tutorial
221
- Requires-Dist: pandas; extra == "tutorial"
222
- Requires-Dist: matplotlib; extra == "tutorial"
223
- Requires-Dist: numpy; extra == "tutorial"
224
- Requires-Dist: scipy; extra == "tutorial"
225
- Requires-Dist: seaborn; extra == "tutorial"
226
- Requires-Dist: dask[distributed]; extra == "tutorial"
227
- Requires-Dist: dask-jobqueue; extra == "tutorial"
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"
228
229
  Description-Content-Type: text/markdown
229
230
 
230
231
  # MUSICA
@@ -0,0 +1,80 @@
1
+ musica/__init__.py,sha256=pSZ-H2IJ4EEYIbQDygjGwjhGySXdeifB1DzQBMJzz2g,403
2
+ musica/_musica.cp39-win_amd64.pyd,sha256=h0E5BtSjv09JNQQDQeggvMkGJzrN9Z0Zd6mKVt6G29o,1820160
3
+ musica/_version.py,sha256=c4IRHcVoNZR6rdRjBv_PU37jj0p2ePPRz7W2q-uSro4,20
4
+ musica/backend.py,sha256=Fw3-HECqsifQmvRonDTGeEZqS-KXYD09BCwBue_HwfM,1081
5
+ musica/binding_common.cpp,sha256=gAmVhVmnLUWMNQXDTjbZPwWOudJl0qObbR2v4MXG7vE,991
6
+ musica/binding_common.hpp,sha256=GMPcEBYI4NkVFeKAQ_EJCJsQrWPBDhzOORvQRmjC_1s,572
7
+ musica/carma.cpp,sha256=v6f2MF1PUGHR46vVZ544o6bEZjCTI2rWvtgL8M0oSns,43244
8
+ musica/carma.py,sha256=FNd4pWJQJ8VJoo2LSl2aXUVSfLZFgABTSKqtTE-Cgv4,68716
9
+ musica/CMakeLists.txt,sha256=FYgmuRSgrsO1dSlwNQy4Wa2FRls2DGE6LAAznDUrxkQ,1887
10
+ musica/constants.py,sha256=sQqh1UVu2HRvl25qWPW0ACT8NrHe_r4Ugy-v_BiTGG4,126
11
+ musica/cpu_binding.cpp,sha256=Cy06zLErMV0g7Ol9Fg-q2cpG-g5fb8hcBl-M-ihHLyk,236
12
+ musica/cuda.cpp,sha256=oTG2ZnL-SiW2kx9eL4XJOQGJeIiGuy8tJ5BEoLRWL4M,358
13
+ musica/cuda.py,sha256=ClHKnSNiU8SX0BANh5KybismYHH6mFUyC-3r8S9qARo,271
14
+ musica/examples/__init__.py,sha256=hR0kZhoHfL9dcup7gg64HDJyIyAQqHAsip8LpuRNnI8,32
15
+ musica/examples/carma_aluminum.py,sha256=Q2IRvU9jxuKAUZvhQkTawVfZV0UADiMvXP-R6uzjemo,3808
16
+ musica/examples/carma_sulfate.py,sha256=MbV1oBrB6rc7yWMxbnYVr_SHlTMqd6uV21kwVhlUymY,8365
17
+ musica/examples/examples.py,sha256=xWnFSNMYPpUhz04YtSSNsr6DoxmQoOdUtTT9GSUm3ps,5901
18
+ musica/examples/sulfate_box_model.py,sha256=LU1kJYtCZNV_4Mi8kJl2V7YQwQuP1dv8Ba4-2vhPFbE,17110
19
+ musica/examples/ts1_latin_hypercube.py,sha256=tLH9swPT4pvDnd7a86-xnt8PqXl4Y7bAXowsA0J7PV8,9868
20
+ musica/gpu_binding.cpp,sha256=X0qISrKYz7Ldjn5UnqNw8oLzOY4VgyF3fUUszm-QSJI,240
21
+ musica/grid.cpp,sha256=Zw32VIrFCzLjYaJhS0BS5QZe9gtJ1U1yshOTRoHSdKg,8769
22
+ musica/grid.py,sha256=MFO5k6uxzDGxTjmwXor1zlTCAqzfe4OtmNIC6RjIgII,3587
23
+ musica/grid_map.cpp,sha256=iV7AQk85dQOCveQwy3rsIKgfyTZzQiz20Gg75BnEHtY,4249
24
+ musica/grid_map.py,sha256=rQzHQOpNiUP5a73OxAgn9mUwRKRrvNson8ojTWtNN-U,5394
25
+ musica/main.py,sha256=gVCfeh44VL4EH7eFRR2wU_I_kANB94furojDi-0LhoE,2797
26
+ musica/mechanism_configuration/__init__.py,sha256=vw3OCq138IgMn-r9tGwL6d-cn7QBsPKmOtqzrmTdNI0,686
27
+ musica/mechanism_configuration/ancillary.py,sha256=lBYSta0nWXbp59gPXkIsr920ysY_oIX3lFgGzEO6mrM,230
28
+ musica/mechanism_configuration/arrhenius.py,sha256=drJyt4aAsjvixMtXCXliZlIv3g2f9usDi208XvBG1Sw,5410
29
+ musica/mechanism_configuration/branched.py,sha256=6LSFRAkcIPWnUjU4FqUYZaYzdcSfTEz2moZQJW3NZRg,5384
30
+ musica/mechanism_configuration/emission.py,sha256=M9cCYgaPrCto5y16UWXfcjt_23-AN41D14vFrgLnwT4,2984
31
+ musica/mechanism_configuration/first_order_loss.py,sha256=nIk-nTrCtkmUjhATXbQ_AsTh0IUtRz73YAicS0bgHSE,3370
32
+ musica/mechanism_configuration/mechanism.py,sha256=w4not9yIvOzS0CNGPFKAvU3vgZpVoJ_mzkLa4mnsphc,3069
33
+ musica/mechanism_configuration/phase.py,sha256=-znETgYbkS3wZnW05BC0wqgDQJI2BOKNQ-F5ncrfB7s,1963
34
+ musica/mechanism_configuration/phase_species.py,sha256=O1_eG8xN4BrABPLdeMWPjozlEC08X0UGJA0Pay0Pxyc,2283
35
+ musica/mechanism_configuration/photolysis.py,sha256=KPs1ts9pUj9XJJd99GAMX4vdxvfcl6Dcn6x1MKKO3Fo,3679
36
+ musica/mechanism_configuration/reaction_component.py,sha256=gS91SwThchLBT-ukz9NkhDSZFqHWBTAL-vvJTZvGiG0,2056
37
+ musica/mechanism_configuration/reactions.py,sha256=x-Qv648H3saSnHNAWAX1jolSNqa85MEXLeMAY5FSFSc,776
38
+ musica/mechanism_configuration/species.py,sha256=NCL6XYEEnBD8FARWFWnWLqpsfpcFVrzbGT7eUzND5Jo,2964
39
+ musica/mechanism_configuration/surface.py,sha256=ViaAjGLhdAICiaSNxaI_gHWBUHBwLSmq7gE2bDRvWO8,3824
40
+ musica/mechanism_configuration/taylor_series.py,sha256=ooDooCuhYy7VRxursVbAOu_YNckHiNyZoDGqw-Av3ew,5533
41
+ musica/mechanism_configuration/ternary_chemical_activation.py,sha256=qRt_5yWo1N_rFQ5BHTY8aGcSDWlpDhlkMmLAvWvuRk0,7066
42
+ musica/mechanism_configuration/troe.py,sha256=HaAB-8i0Hk9XNUulkUElTkxnkXhjjg6YM-Tn1ITVWsg,6553
43
+ musica/mechanism_configuration/tunneling.py,sha256=Nbve_L2pZ9_SMp5_qzPEKTPsgib1wb2cBJBLvvzPfIE,4439
44
+ musica/mechanism_configuration/user_defined.py,sha256=Bcv9JQ5R--34xQpfuJOJc9-91RUhGyBueFx3tUlxxgY,3768
45
+ musica/mechanism_configuration/utils.py,sha256=dhMFrydNchhdRrfeJw35oJB8Y5oQJa6p65Z7I127P-8,356
46
+ musica/mechanism_configuration.cpp,sha256=62ws5qLkUPOnDapSNQ0Z9ZkZ8a4N-eutBuR1L-VymCY,22929
47
+ musica/musica.cpp,sha256=eVHiG898fg39n62hOkfxH1xld4ejAXgSepJTFPJEuDM,8420
48
+ musica/profile.cpp,sha256=ZMdtMKEAjZE5c_ds1WSkGPsYqsJIH0kQw_IO9m4abcc,12775
49
+ musica/profile.py,sha256=kAYPmxKkwTwTcAlaU2Ip3ToDxFzbFguODHagPgkJh5A,3712
50
+ musica/profile_map.cpp,sha256=oxj8TTLSm-s5K7B3DUhUvXN1YOEpbFoQbL8Y_2gEY7Y,4379
51
+ musica/profile_map.py,sha256=2Zx_fMCZx1vEwTGwpS_ZhXzO6Hr8KiBR_yNj6RNXlxA,5673
52
+ musica/test/examples/v1/full_configuration/full_configuration.json,sha256=v9ircJPE8QxaIxsBJs1-GM42tfTMfJdWVChj1oZGbM0,6472
53
+ musica/test/examples/v1/full_configuration/full_configuration.yaml,sha256=hdZpOm9y6u79j_mszEFiy8u7Put9k_6eZ36-LGIlkZU,4147
54
+ musica/test/integration/test_analytical.py,sha256=eOPb3DtjQEodTZCpjelw1LQZM_VyhFi2TOlx1bmEtkk,14129
55
+ musica/test/integration/test_carma.py,sha256=itPJNxSRp7FHJokYSicZFgqzBBrZ9dr1TDxawDPT9BM,7092
56
+ musica/test/integration/test_carma_aluminum.py,sha256=F7_8xwZnKjSxgnZKdZR1tDwzwfVUiD7ZT1b_9cseE3M,368
57
+ musica/test/integration/test_carma_sulfate.py,sha256=OWQDLQNao5vU2FAMpWDVqs8xrFhpxvRfhx8HrP6GTCs,759
58
+ musica/test/integration/test_chapman.py,sha256=igtiyoiT1OjvT0bA7lvGxVzBlh0ElNNrWVEr5s-9GvQ,3621
59
+ musica/test/integration/test_sulfate_box_model.py,sha256=umqG0PAaCu27J3s5W_cnWJt9T_9EFox9z_JMHKNz5GI,1638
60
+ musica/test/integration/test_tuvx.py,sha256=fOaOzlupFOJJGlbhZfH_-_Wdh6DTSx_rVXBcGYxOW2M,5748
61
+ musica/test/unit/test_grid.py,sha256=sTUG_6uF_8F3PJHNnhaNf46LiAeBkI-yezGW3CYVK88,4602
62
+ musica/test/unit/test_grid_map.py,sha256=cAUqCFL1nmXmh_RWstTjj8HgaIDkyu0ESR1DdMErgVk,3646
63
+ musica/test/unit/test_parser.py,sha256=-HUQXfsr3auMFv5f9SvAUskkcUpPG32b2l3XYU7aHJ0,2378
64
+ musica/test/unit/test_profile.py,sha256=CKRAnAN1aNBz3zGVZgQtRNeFccNvjHLq9bIb7yDDKbg,6703
65
+ musica/test/unit/test_profile_map.py,sha256=uPADG32XXaa8x23TgpeB_H-5CivLfl9v_jTkP9xeudk,4693
66
+ musica/test/unit/test_serializer.py,sha256=gvRQDbn3MadHqZvlUYcrtFWMMcH7LGZ4VnKq477bvVg,2198
67
+ musica/test/unit/test_state.py,sha256=Mlo5UFhj4fvOu2sqB1E0xPnhLWs9ocJhnPTnR_PZojU,11210
68
+ musica/test/unit/test_util_full_mechanism.py,sha256=3zvr8TNc2y7KMU2wYQzabcfsGs95sfppPpjCKnRqTic,16831
69
+ musica/tools/prepare_build_environment_linux.sh,sha256=i69LuyY25KE-jFIFNuYC4_33_DGTngentBvt2Tbed9g,1017
70
+ musica/tools/prepare_build_environment_macos.sh,sha256=Yhhd-8W6YvR79NabEqixexU6BsClNf7DH_EYYlsmeMo,41
71
+ musica/tools/repair_wheel_gpu.sh,sha256=nQueyGNC2qWcBAicjVdAfB6JH4m_51dFOG83vVxke54,1525
72
+ musica/tuvx.cpp,sha256=2JHst374H8lIKLTptmEogY0YqMhfwKyponh3FtL54u4,6415
73
+ musica/tuvx.py,sha256=kAa3tGMoTWD1Gvay-n-ST2k29BqtaMnER9G9PzuFcZc,9184
74
+ musica/types.py,sha256=9OErDNWwkoNU2rkB8Q4Vo8zbDjO0vGkBK_T984LiX48,17540
75
+ musica-0.13.0.dist-info/METADATA,sha256=TH2C-ia8-RRs9ea99MPrN5uk24JBz85UisjjvgjfccY,26422
76
+ musica-0.13.0.dist-info/WHEEL,sha256=9tsL4JT94eZPTkcS3bNng2riasYJMxXndrO9CxUfJHs,104
77
+ musica-0.13.0.dist-info/entry_points.txt,sha256=t9qRU9Ya63_yYMKJkTiVS5kCaW6dDDr0wuQ26lgXTH8,49
78
+ musica-0.13.0.dist-info/licenses/AUTHORS.md,sha256=1ssAXR4WOMdfl5Or1raPu_2nxHbkwCpxfwJwzpF_cJM,2691
79
+ musica-0.13.0.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
80
+ musica-0.13.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: scikit-build-core 0.11.5
2
+ Generator: scikit-build-core 0.11.6
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp39-cp39-win_amd64
5
5