musica 0.11.1.3__cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl → 0.12.0__cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.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 (54) hide show
  1. musica/CMakeLists.txt +35 -40
  2. musica/__init__.py +51 -3
  3. musica/_musica.cpython-311-i386-linux-gnu.so +0 -0
  4. musica/_version.py +1 -1
  5. musica/binding_common.cpp +16 -0
  6. musica/binding_common.hpp +7 -0
  7. musica/constants.py +3 -0
  8. musica/cpu_binding.cpp +10 -0
  9. musica/cuda.cpp +12 -0
  10. musica/cuda.py +10 -0
  11. musica/gpu_binding.cpp +10 -0
  12. musica/mechanism_configuration/__init__.py +1 -0
  13. musica/mechanism_configuration/aqueous_equilibrium.py +101 -0
  14. musica/mechanism_configuration/arrhenius.py +121 -0
  15. musica/mechanism_configuration/branched.py +116 -0
  16. musica/mechanism_configuration/condensed_phase_arrhenius.py +116 -0
  17. musica/mechanism_configuration/condensed_phase_photolysis.py +91 -0
  18. musica/mechanism_configuration/emission.py +67 -0
  19. musica/mechanism_configuration/first_order_loss.py +67 -0
  20. musica/mechanism_configuration/henrys_law.py +85 -0
  21. musica/mechanism_configuration/mechanism_configuration.py +161 -0
  22. musica/mechanism_configuration/phase.py +43 -0
  23. musica/mechanism_configuration/photolysis.py +83 -0
  24. musica/mechanism_configuration/reactions.py +61 -0
  25. musica/mechanism_configuration/simpol_phase_transfer.py +88 -0
  26. musica/mechanism_configuration/species.py +72 -0
  27. musica/mechanism_configuration/surface.py +89 -0
  28. musica/mechanism_configuration/troe.py +137 -0
  29. musica/mechanism_configuration/tunneling.py +103 -0
  30. musica/mechanism_configuration/user_defined.py +83 -0
  31. musica/mechanism_configuration/utils.py +10 -0
  32. musica/mechanism_configuration/wet_deposition.py +49 -0
  33. musica/mechanism_configuration.cpp +0 -1
  34. musica/musica.cpp +1 -1
  35. musica/test/examples/v1/{full_configuration.json → full_configuration/full_configuration.json} +30 -15
  36. musica/test/examples/v1/{full_configuration.yaml → full_configuration/full_configuration.yaml} +16 -1
  37. musica/test/test_analytical.py +14 -12
  38. musica/test/test_chapman.py +18 -2
  39. musica/test/test_parser.py +4 -640
  40. musica/test/test_serializer.py +69 -0
  41. musica/test/test_util_full_mechanism.py +668 -0
  42. musica/tools/prepare_build_environment_linux.sh +8 -6
  43. musica/tools/repair_wheel_gpu.sh +25 -16
  44. musica/types.py +4 -6
  45. {musica-0.11.1.3.dist-info → musica-0.12.0.dist-info}/METADATA +179 -43
  46. musica-0.12.0.dist-info/RECORD +57 -0
  47. {musica-0.11.1.3.dist-info → musica-0.12.0.dist-info}/WHEEL +1 -1
  48. musica-0.12.0.dist-info/licenses/AUTHORS.md +59 -0
  49. musica/binding.cpp +0 -19
  50. musica/lib/libmusica.a +0 -0
  51. musica/lib/libyaml-cpp.a +0 -0
  52. musica/mechanism_configuration.py +0 -1291
  53. musica-0.11.1.3.dist-info/RECORD +0 -30
  54. {musica-0.11.1.3.dist-info → musica-0.12.0.dist-info}/licenses/LICENSE +0 -0
musica/CMakeLists.txt CHANGED
@@ -1,47 +1,42 @@
1
- pybind11_add_module(_musica
2
- binding.cpp
3
- musica.cpp
4
- mechanism_configuration.cpp
5
- )
1
+ ################################################################################
2
+ # Python Extension Modules
3
+
4
+ #include(setup_muisca_target)
5
+
6
+ # Define the list of Python extension module targets
7
+ set(PY_MODULES _musica)
8
+
9
+ set(
10
+ MUSICA_PYTHON_SOURCES
11
+ binding_common.cpp
12
+ cuda.cpp
13
+ mechanism_configuration.cpp
14
+ musica.cpp
6
15
 
7
- target_link_libraries(_musica
8
- PRIVATE
9
- musica::musica
16
+ ${MUSICA_SOURCES}
10
17
  )
11
18
 
12
- include(silence_warnings)
13
- silence_warnings(_musica)
14
-
15
- if (APPLE)
16
- # set the rpath for the shared library
17
- set_target_properties(_musica PROPERTIES
18
- INSTALL_RPATH "@loader_path"
19
- BUILD_WITH_INSTALL_RPATH TRUE
20
- )
21
- elseif(UNIX)
22
- set_target_properties(_musica PROPERTIES
23
- INSTALL_RPATH "$ORIGIN"
24
- BUILD_WITH_INSTALL_RPATH TRUE
25
- )
26
- endif()
19
+ pybind11_add_module(_musica cpu_binding.cpp ${MUSICA_PYTHON_SOURCES})
20
+ musica_setup_target(_musica MODE CPU)
27
21
 
28
- if(WIN32)
29
- # makefiles on windows don't need the config directory
30
- if (${CMAKE_GENERATOR} MATCHES "MinGW Makefiles")
31
- set(PYTHON_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}")
32
- else()
33
- # but visual studio does
34
- set(PYTHON_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
35
- endif()
36
- else()
37
- set(PYTHON_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}")
22
+ if (NOT ${MUSICA_GPU_TYPE} STREQUAL "None")
23
+ pybind11_add_module(_musica_gpu gpu_binding.cpp ${MUSICA_PYTHON_SOURCES})
24
+ musica_setup_target(_musica_gpu MODE GPU)
25
+ list(APPEND PY_MODULES _musica_gpu)
38
26
  endif()
39
27
 
40
- install(TARGETS _musica LIBRARY DESTINATION musica)
28
+ foreach(lib ${PY_MODULES})
29
+ if (APPLE)
30
+ set_target_properties(${lib} PROPERTIES
31
+ INSTALL_RPATH "@loader_path"
32
+ BUILD_WITH_INSTALL_RPATH TRUE
33
+ )
34
+ elseif(UNIX)
35
+ set_target_properties(${lib} PROPERTIES
36
+ INSTALL_RPATH "$ORIGIN"
37
+ BUILD_WITH_INSTALL_RPATH TRUE
38
+ )
39
+ endif()
41
40
 
42
- install(
43
- TARGETS
44
- yaml-cpp musica
45
- LIBRARY DESTINATION musica/lib
46
- ARCHIVE DESTINATION musica/lib
47
- )
41
+ install(TARGETS ${lib} LIBRARY DESTINATION musica)
42
+ endforeach()
musica/__init__.py CHANGED
@@ -1,3 +1,51 @@
1
- from musica._musica import *
2
- from .types import *
3
- from .mechanism_configuration import *
1
+ import importlib.util
2
+
3
+
4
+ def _safe_find_spec(name):
5
+ try:
6
+ return importlib.util.find_spec(name)
7
+ except ModuleNotFoundError:
8
+ return None
9
+
10
+
11
+ def _gpu_deps_installed():
12
+ return (
13
+ _safe_find_spec("nvidia.cublas") is not None or
14
+ _safe_find_spec("nvidia_cuda_runtime") is not None or
15
+ _safe_find_spec("nvidia-cublas-cu12") is not None or
16
+ _safe_find_spec("nvidia-cuda-runtime-cu12") is not None
17
+ )
18
+
19
+
20
+ if _gpu_deps_installed():
21
+ from . import _musica_gpu as _backend
22
+ else:
23
+ from . import _musica as _backend
24
+
25
+ # Helper to re-export names from a module
26
+ def _export_all(module, names, globals_):
27
+ for name in names:
28
+ globals_[name] = getattr(module, name)
29
+
30
+
31
+ _core_names = [
32
+ "_Conditions", "_SolverType", "_Solver", "_State", "_create_solver",
33
+ "_create_solver_from_mechanism", "_create_state", "_micm_solve", "_vector_size",
34
+ "_species_ordering", "_user_defined_rate_parameters_ordering",
35
+ ]
36
+ _mechanism_names = [
37
+ "_ReactionType", "_Species", "_Phase", "_ReactionComponent", "_Arrhenius",
38
+ "_CondensedPhaseArrhenius", "_Troe", "_Branched", "_Tunneling", "_Surface",
39
+ "_Photolysis", "_CondensedPhasePhotolysis", "_Emission", "_FirstOrderLoss",
40
+ "_AqueousEquilibrium", "_WetDeposition", "_HenrysLaw", "_SimpolPhaseTransfer",
41
+ "_UserDefined", "_Reactions", "_ReactionsIterator", "_Mechanism", "_Version", "_Parser"
42
+ ]
43
+
44
+ # this allows us to use the same symbols in both the GPU and CPU versionspp
45
+ _export_all(_backend._core, _core_names, globals())
46
+ _export_all(_backend._mechanism_configuration, _mechanism_names, globals())
47
+
48
+ __all__ = _core_names + _mechanism_names
49
+
50
+ from .types import MICM, SolverType, State, Conditions
51
+ from ._version import version as __version__
musica/_version.py CHANGED
@@ -1 +1 @@
1
- version = "0.11.1.3"
1
+ version = "0.12.0"
@@ -0,0 +1,16 @@
1
+ #include "binding_common.hpp"
2
+
3
+ void bind_cuda(py::module_ &);
4
+ void bind_musica(py::module_ &);
5
+
6
+ void bind_mechanism_configuration(py::module_ &);
7
+
8
+ void bind_all(py::module_ &m) {
9
+ py::module_ core = m.def_submodule("_core", "Wrapper classes for MUSICA C library structs and functions");
10
+ py::module_ mechanism_configuration = m.def_submodule("_mechanism_configuration", "Wrapper classes for Mechanism Configuration library structs and functions");
11
+
12
+ bind_cuda(core);
13
+ bind_musica(core);
14
+
15
+ bind_mechanism_configuration(mechanism_configuration);
16
+ }
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+
3
+ #include <pybind11/pybind11.h>
4
+
5
+ namespace py = pybind11;
6
+
7
+ void bind_all(py::module_ &m);
musica/constants.py ADDED
@@ -0,0 +1,3 @@
1
+ AVOGADRO = 6.02214076e23 # mol^-1
2
+ BOLTZMANN = 1.380649e-23 # J K^-1
3
+ GAS_CONSTANT = AVOGADRO * BOLTZMANN # J K^-1 mol^-1
musica/cpu_binding.cpp ADDED
@@ -0,0 +1,10 @@
1
+ // Copyright (C) 2023-2025 University Corporation for Atmospheric Research
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ #include <pybind11/pybind11.h>
5
+ #include "binding_common.hpp"
6
+
7
+ PYBIND11_MODULE(_musica, m)
8
+ {
9
+ bind_all(m);
10
+ }
musica/cuda.cpp ADDED
@@ -0,0 +1,12 @@
1
+ // Copyright (C) 2023-2025 University Corporation for Atmospheric Research
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ #include <musica/micm/cuda_availability.hpp>
4
+
5
+ #include <pybind11/pybind11.h>
6
+
7
+ namespace py = pybind11;
8
+
9
+ void bind_cuda(py::module_ &cuda)
10
+ {
11
+ cuda.def("_is_cuda_available", &musica::IsCudaAvailable, "Check if CUDA is available");
12
+ }
musica/cuda.py ADDED
@@ -0,0 +1,10 @@
1
+ from . import _backend
2
+
3
+ def is_cuda_available() -> bool:
4
+ """
5
+ Check if CUDA is available.
6
+
7
+ Returns:
8
+ bool: True if CUDA is available, False otherwise.
9
+ """
10
+ return _backend._core._is_cuda_available()
musica/gpu_binding.cpp ADDED
@@ -0,0 +1,10 @@
1
+ // Copyright (C) 2023-2025 University Corporation for Atmospheric Research
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ #include <pybind11/pybind11.h>
5
+ #include "binding_common.hpp"
6
+
7
+ PYBIND11_MODULE(_musica_gpu, m)
8
+ {
9
+ bind_all(m);
10
+ }
@@ -0,0 +1 @@
1
+ from .mechanism_configuration import *
@@ -0,0 +1,101 @@
1
+ from typing import Optional, Any, Dict, List, Union, Tuple
2
+ from musica import _AqueousEquilibrium, _ReactionComponent
3
+ from .phase import Phase
4
+ from .species import Species
5
+ from .reactions import ReactionComponentSerializer
6
+ from .utils import _add_other_properties, _remove_empty_keys
7
+
8
+
9
+ class AqueousEquilibrium(_AqueousEquilibrium):
10
+ """
11
+ A class representing an aqueous equilibrium reaction rate constant.
12
+
13
+ Attributes:
14
+ name (str): The name of the aqueous equilibrium reaction rate constant.
15
+ gas_phase (Phase): The gas phase in which the reaction occurs.
16
+ aerosol_phase (Phase): The aerosol phase in which the reaction occurs.
17
+ aerosol_phase_water (Species): The water species in the aerosol phase.
18
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
19
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
20
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1].
21
+ C (float): Exponential term [K-1].
22
+ k_reverse (float): Reverse rate constant [(mol m-3)^(n-1)s-1].
23
+ other_properties (Dict[str, Any]): A dictionary of other properties of the aqueous equilibrium reaction rate constant.
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ name: Optional[str] = None,
29
+ aerosol_phase: Optional[Phase] = None,
30
+ aerosol_phase_water: Optional[Species] = None,
31
+ reactants: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
32
+ products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
33
+ A: Optional[float] = None,
34
+ C: Optional[float] = None,
35
+ k_reverse: Optional[float] = None,
36
+ other_properties: Optional[Dict[str, Any]] = None,
37
+ ):
38
+ """
39
+ Initializes the AqueousEquilibrium object with the given parameters.
40
+
41
+ Args:
42
+ name (str): The name of the aqueous equilibrium reaction rate constant.
43
+ aerosol_phase (Phase): The aerosol phase in which the reaction occurs.
44
+ aerosol_phase_water (Species): The water species in the aerosol phase.
45
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
46
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
47
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1].
48
+ C (float): Exponential term [K-1].
49
+ k_reverse (float): Reverse rate constant [(mol m-3)^(n-1)s-1].
50
+ other_properties (Dict[str, Any]): A dictionary of other properties of the aqueous equilibrium reaction rate constant.
51
+ """
52
+ super().__init__()
53
+ self.name = name if name is not None else self.name
54
+ self.aerosol_phase = aerosol_phase.name if aerosol_phase is not None else self.aerosol_phase
55
+ self.aerosol_phase_water = (
56
+ aerosol_phase_water.name if aerosol_phase_water is not None else self.aerosol_phase_water
57
+ )
58
+ self.reactants = (
59
+ [
60
+ (
61
+ _ReactionComponent(r.name)
62
+ if isinstance(r, Species)
63
+ else _ReactionComponent(r[1].name, r[0])
64
+ )
65
+ for r in reactants
66
+ ]
67
+ if reactants is not None
68
+ else self.reactants
69
+ )
70
+ self.products = (
71
+ [
72
+ (
73
+ _ReactionComponent(p.name)
74
+ if isinstance(p, Species)
75
+ else _ReactionComponent(p[1].name, p[0])
76
+ )
77
+ for p in products
78
+ ]
79
+ if products is not None
80
+ else self.products
81
+ )
82
+ self.A = A if A is not None else self.A
83
+ self.C = C if C is not None else self.C
84
+ self.k_reverse = k_reverse if k_reverse is not None else self.k_reverse
85
+ self.other_properties = other_properties if other_properties is not None else self.other_properties
86
+
87
+ @staticmethod
88
+ def serialize(instance) -> Dict:
89
+ serialize_dict = {
90
+ "type": "AQUEOUS_EQUILIBRIUM",
91
+ "name": instance.name,
92
+ "aerosol phase": instance.aerosol_phase,
93
+ "aerosol-phase water": instance.aerosol_phase_water,
94
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(instance.reactants),
95
+ "products": ReactionComponentSerializer.serialize_list_reaction_components(instance.products),
96
+ "A": instance.A,
97
+ "C": instance.C,
98
+ "k_reverse": instance.k_reverse,
99
+ }
100
+ _add_other_properties(serialize_dict, instance.other_properties)
101
+ return _remove_empty_keys(serialize_dict)
@@ -0,0 +1,121 @@
1
+ from typing import Optional, Any, Dict, List, Union, Tuple
2
+ from musica import _Arrhenius, _ReactionComponent
3
+ from .phase import Phase
4
+ from .species import Species
5
+ from .reactions import ReactionComponentSerializer
6
+ from .utils import _add_other_properties, _remove_empty_keys
7
+ from musica.constants import BOLTZMANN
8
+
9
+
10
+ class Arrhenius(_Arrhenius):
11
+ """
12
+ A class representing an Arrhenius rate constant.
13
+
14
+ k = A * exp( C / T ) * ( T / D )^B * exp( 1 - E * P )
15
+
16
+ where:
17
+ k = rate constant
18
+ A = pre-exponential factor [(mol m-3)^(n-1)s-1]
19
+ B = temperature exponent [unitless]
20
+ C = exponential term [K-1]
21
+ D = reference temperature [K]
22
+ E = pressure scaling term [Pa-1]
23
+ T = temperature [K]
24
+ P = pressure [Pa]
25
+ n = number of reactants
26
+
27
+ Attributes:
28
+ name (str): The name of the Arrhenius rate constant.
29
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1] where n is the number of reactants.
30
+ B (float): Temperature exponent [unitless].
31
+ C (float): Exponential term [K-1].
32
+ D (float): Reference Temperature [K].
33
+ E (float): Pressure scaling term [Pa-1].
34
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
35
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
36
+ gas_phase (Phase): The gas phase in which the reaction occurs.
37
+ other_properties (Dict[str, Any]): A dictionary of other properties of the Arrhenius rate constant.
38
+ """
39
+
40
+ def __init__(
41
+ self,
42
+ name: Optional[str] = None,
43
+ A: Optional[float] = None,
44
+ B: Optional[float] = None,
45
+ C: Optional[float] = None,
46
+ Ea: Optional[float] = None,
47
+ D: Optional[float] = None,
48
+ E: Optional[float] = None,
49
+ reactants: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
50
+ products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
51
+ gas_phase: Optional[Phase] = None,
52
+ other_properties: Optional[Dict[str, Any]] = None,
53
+ ):
54
+ """
55
+ Initializes the Arrhenius object with the given parameters.
56
+
57
+ Args:
58
+ name (str): The name of the Arrhenius rate constant.
59
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1] where n is the number of reactants.
60
+ B (float): Temperature exponent [unitless].
61
+ C (float): Exponential term [K-1].
62
+ Ea (float): Activation energy [J molecule-1].
63
+ D (float): Reference Temperature [K].
64
+ E (float): Pressure scaling term [Pa-1].
65
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
66
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
67
+ gas_phase (Phase): The gas phase in which the reaction occurs.
68
+ other_properties (Dict[str, Any]): A dictionary of other properties of the Arrhenius rate constant.
69
+ """
70
+ super().__init__()
71
+ self.name = name if name is not None else self.name
72
+ self.A = A if A is not None else self.A
73
+ self.B = B if B is not None else self.B
74
+ if C is not None and Ea is not None:
75
+ raise ValueError("Cannot specify both C and Ea.")
76
+ self.C = -Ea / BOLTZMANN if Ea is not None else C if C is not None else self.C
77
+ self.D = D if D is not None else self.D
78
+ self.E = E if E is not None else self.E
79
+ self.reactants = (
80
+ [
81
+ (
82
+ _ReactionComponent(r.name)
83
+ if isinstance(r, Species)
84
+ else _ReactionComponent(r[1].name, r[0])
85
+ )
86
+ for r in reactants
87
+ ]
88
+ if reactants is not None
89
+ else self.reactants
90
+ )
91
+ self.products = (
92
+ [
93
+ (
94
+ _ReactionComponent(p.name)
95
+ if isinstance(p, Species)
96
+ else _ReactionComponent(p[1].name, p[0])
97
+ )
98
+ for p in products
99
+ ]
100
+ if products is not None
101
+ else self.products
102
+ )
103
+ self.gas_phase = gas_phase.name if gas_phase is not None else self.gas_phase
104
+ self.other_properties = other_properties if other_properties is not None else self.other_properties
105
+
106
+ @staticmethod
107
+ def serialize(instance) -> Dict:
108
+ serialize_dict = {
109
+ "type": "ARRHENIUS",
110
+ "name": instance.name,
111
+ "A": instance.A,
112
+ "B": instance.B,
113
+ "C": instance.C,
114
+ "D": instance.D,
115
+ "E": instance.E,
116
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(instance.reactants),
117
+ "products": ReactionComponentSerializer.serialize_list_reaction_components(instance.products),
118
+ "gas phase": instance.gas_phase,
119
+ }
120
+ _add_other_properties(serialize_dict, instance.other_properties)
121
+ return _remove_empty_keys(serialize_dict)
@@ -0,0 +1,116 @@
1
+ from typing import Optional, Any, Dict, List, Union, Tuple
2
+ from musica import _Branched, _ReactionComponent
3
+ from .phase import Phase
4
+ from .species import Species
5
+ from .reactions import ReactionComponentSerializer
6
+ from .utils import _add_other_properties, _remove_empty_keys
7
+
8
+
9
+ class Branched(_Branched):
10
+ """
11
+ A class representing a branched reaction rate constant.
12
+
13
+ (TODO: get details from MusicBox)
14
+
15
+ Attributes:
16
+ name (str): The name of the branched reaction rate constant.
17
+ X (float): Pre-exponential branching factor [(mol m-3)^-(n-1)s-1].
18
+ Y (float): Exponential branching factor [K-1].
19
+ a0 (float): Z parameter [unitless].
20
+ n (float): A parameter [unitless].
21
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
22
+ nitrate_products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the nitrate branch.
23
+ alkoxy_products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the alkoxy branch.
24
+ gas_phase (Phase): The gas phase in which the reaction occurs.
25
+ other_properties (Dict[str, Any]): A dictionary of other properties of the branched reaction rate constant.
26
+ """
27
+
28
+ def __init__(
29
+ self,
30
+ name: Optional[str] = None,
31
+ X: Optional[float] = None,
32
+ Y: Optional[float] = None,
33
+ a0: Optional[float] = None,
34
+ n: Optional[float] = None,
35
+ reactants: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
36
+ nitrate_products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
37
+ alkoxy_products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
38
+ gas_phase: Optional[Phase] = None,
39
+ other_properties: Optional[Dict[str, Any]] = None,
40
+ ):
41
+ """
42
+ Initializes the Branched object with the given parameters.
43
+
44
+ Args:
45
+ name (str): The name of the branched reaction rate constant.
46
+ X (float): Pre-exponential branching factor [(mol m-3)^-(n-1)s-1].
47
+ Y (float): Exponential branching factor [K-1].
48
+ a0 (float): Z parameter [unitless].
49
+ n (float): A parameter [unitless].
50
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
51
+ nitrate_products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the nitrate branch.
52
+ alkoxy_products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the alkoxy branch.
53
+ gas_phase (Phase): The gas phase in which the reaction occurs.
54
+ other_properties (Dict[str, Any]): A dictionary of other properties of the branched reaction rate constant.
55
+ """
56
+ super().__init__()
57
+ self.name = name if name is not None else self.name
58
+ self.X = X if X is not None else self.X
59
+ self.Y = Y if Y is not None else self.Y
60
+ self.a0 = a0 if a0 is not None else self.a0
61
+ self.n = n if n is not None else self.n
62
+ self.reactants = (
63
+ [
64
+ (
65
+ _ReactionComponent(r.name)
66
+ if isinstance(r, Species)
67
+ else _ReactionComponent(r[1].name, r[0])
68
+ )
69
+ for r in reactants
70
+ ]
71
+ if reactants is not None
72
+ else self.reactants
73
+ )
74
+ self.nitrate_products = (
75
+ [
76
+ (
77
+ _ReactionComponent(p.name)
78
+ if isinstance(p, Species)
79
+ else _ReactionComponent(p[1].name, p[0])
80
+ )
81
+ for p in nitrate_products
82
+ ]
83
+ if nitrate_products is not None
84
+ else self.nitrate_products
85
+ )
86
+ self.alkoxy_products = (
87
+ [
88
+ (
89
+ _ReactionComponent(p.name)
90
+ if isinstance(p, Species)
91
+ else _ReactionComponent(p[1].name, p[0])
92
+ )
93
+ for p in alkoxy_products
94
+ ]
95
+ if alkoxy_products is not None
96
+ else self.alkoxy_products
97
+ )
98
+ self.gas_phase = gas_phase.name if gas_phase is not None else self.gas_phase
99
+ self.other_properties = other_properties if other_properties is not None else self.other_properties
100
+
101
+ @staticmethod
102
+ def serialize(instance) -> Dict:
103
+ serialize_dict = {
104
+ "type": "BRANCHED_NO_RO2",
105
+ "name": instance.name,
106
+ "X": instance.X,
107
+ "Y": instance.Y,
108
+ "a0": instance.a0,
109
+ "n": instance.n,
110
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(instance.reactants),
111
+ "nitrate products": ReactionComponentSerializer.serialize_list_reaction_components(instance.nitrate_products),
112
+ "alkoxy products": ReactionComponentSerializer.serialize_list_reaction_components(instance.alkoxy_products),
113
+ "gas phase": instance.gas_phase,
114
+ }
115
+ _add_other_properties(serialize_dict, instance.other_properties)
116
+ return _remove_empty_keys(serialize_dict)