musica 0.12.2__cp310-cp310-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.

Files changed (80) hide show
  1. musica/.dylibs/libaec.0.1.4.dylib +0 -0
  2. musica/.dylibs/libgcc_s.1.1.dylib +0 -0
  3. musica/.dylibs/libgfortran.5.dylib +0 -0
  4. musica/.dylibs/libhdf5.310.5.1.dylib +0 -0
  5. musica/.dylibs/libhdf5_hl.310.0.6.dylib +0 -0
  6. musica/.dylibs/libnetcdf.22.dylib +0 -0
  7. musica/.dylibs/libnetcdff.7.1.0.dylib +0 -0
  8. musica/.dylibs/libquadmath.0.dylib +0 -0
  9. musica/.dylibs/libsz.2.0.1.dylib +0 -0
  10. musica/.dylibs/libzstd.1.5.7.dylib +0 -0
  11. musica/CMakeLists.txt +68 -0
  12. musica/__init__.py +11 -0
  13. musica/_musica.cpython-310-darwin.so +0 -0
  14. musica/_version.py +1 -0
  15. musica/backend.py +41 -0
  16. musica/binding_common.cpp +33 -0
  17. musica/binding_common.hpp +7 -0
  18. musica/carma.cpp +911 -0
  19. musica/carma.py +1729 -0
  20. musica/constants.py +3 -0
  21. musica/cpu_binding.cpp +11 -0
  22. musica/cuda.cpp +12 -0
  23. musica/cuda.py +13 -0
  24. musica/examples/__init__.py +1 -0
  25. musica/examples/carma_aluminum.py +124 -0
  26. musica/examples/carma_sulfate.py +246 -0
  27. musica/examples/examples.py +165 -0
  28. musica/examples/sulfate_box_model.py +439 -0
  29. musica/examples/ts1_latin_hypercube.py +245 -0
  30. musica/gpu_binding.cpp +11 -0
  31. musica/main.py +89 -0
  32. musica/mechanism_configuration/__init__.py +1 -0
  33. musica/mechanism_configuration/aqueous_equilibrium.py +274 -0
  34. musica/mechanism_configuration/arrhenius.py +307 -0
  35. musica/mechanism_configuration/branched.py +299 -0
  36. musica/mechanism_configuration/condensed_phase_arrhenius.py +309 -0
  37. musica/mechanism_configuration/condensed_phase_photolysis.py +88 -0
  38. musica/mechanism_configuration/emission.py +71 -0
  39. musica/mechanism_configuration/first_order_loss.py +174 -0
  40. musica/mechanism_configuration/henrys_law.py +44 -0
  41. musica/mechanism_configuration/mechanism_configuration.py +234 -0
  42. musica/mechanism_configuration/phase.py +47 -0
  43. musica/mechanism_configuration/photolysis.py +88 -0
  44. musica/mechanism_configuration/reactions.py +73 -0
  45. musica/mechanism_configuration/simpol_phase_transfer.py +217 -0
  46. musica/mechanism_configuration/species.py +91 -0
  47. musica/mechanism_configuration/surface.py +94 -0
  48. musica/mechanism_configuration/ternary_chemical_activation.py +352 -0
  49. musica/mechanism_configuration/troe.py +352 -0
  50. musica/mechanism_configuration/tunneling.py +250 -0
  51. musica/mechanism_configuration/user_defined.py +88 -0
  52. musica/mechanism_configuration/utils.py +10 -0
  53. musica/mechanism_configuration/wet_deposition.py +52 -0
  54. musica/mechanism_configuration.cpp +607 -0
  55. musica/musica.cpp +201 -0
  56. musica/test/examples/v1/full_configuration/full_configuration.json +466 -0
  57. musica/test/examples/v1/full_configuration/full_configuration.yaml +295 -0
  58. musica/test/integration/test_analytical.py +324 -0
  59. musica/test/integration/test_carma.py +227 -0
  60. musica/test/integration/test_carma_aluminum.py +12 -0
  61. musica/test/integration/test_carma_sulfate.py +17 -0
  62. musica/test/integration/test_chapman.py +139 -0
  63. musica/test/integration/test_sulfate_box_model.py +34 -0
  64. musica/test/integration/test_tuvx.py +62 -0
  65. musica/test/unit/test_parser.py +64 -0
  66. musica/test/unit/test_serializer.py +69 -0
  67. musica/test/unit/test_state.py +325 -0
  68. musica/test/unit/test_util_full_mechanism.py +698 -0
  69. musica/tools/prepare_build_environment_linux.sh +32 -0
  70. musica/tools/prepare_build_environment_macos.sh +1 -0
  71. musica/tools/repair_wheel_gpu.sh +40 -0
  72. musica/tuvx.cpp +93 -0
  73. musica/tuvx.py +199 -0
  74. musica/types.py +407 -0
  75. musica-0.12.2.dist-info/METADATA +473 -0
  76. musica-0.12.2.dist-info/RECORD +80 -0
  77. musica-0.12.2.dist-info/WHEEL +6 -0
  78. musica-0.12.2.dist-info/entry_points.txt +3 -0
  79. musica-0.12.2.dist-info/licenses/AUTHORS.md +59 -0
  80. musica-0.12.2.dist-info/licenses/LICENSE +201 -0
musica/main.py ADDED
@@ -0,0 +1,89 @@
1
+ import argparse
2
+ import datetime
3
+ import logging
4
+ import shutil
5
+ import os
6
+ from musica import Examples
7
+ from musica import __version__
8
+ import musica.examples
9
+ import importlib.resources as ir
10
+
11
+
12
+ def format_examples_help(examples):
13
+ return '\n'.join(f"{e.short_name}: {e.description}" for e in examples)
14
+
15
+
16
+ def parse_arguments():
17
+ parser = argparse.ArgumentParser(
18
+ description='musica CLI',
19
+ formatter_class=argparse.RawTextHelpFormatter
20
+ )
21
+ parser.add_argument(
22
+ '-e', '--example',
23
+ type=str,
24
+ choices=[e.short_name for e in Examples],
25
+ help=f'Name of the example to copy out.\nAvailable examples:\n{format_examples_help(Examples)}'
26
+ )
27
+ parser.add_argument(
28
+ '-o', '--output',
29
+ type=str,
30
+ action="append",
31
+ help=("Path to save the example script to.")
32
+ )
33
+ parser.add_argument(
34
+ '-v', '--verbose',
35
+ action='count',
36
+ default=0,
37
+ help='Increase logging verbosity. Use -v for info, -vv for debug.'
38
+ )
39
+ parser.add_argument(
40
+ '--version',
41
+ action='version',
42
+ version=f'musica {__version__}',
43
+ )
44
+ return parser.parse_args()
45
+
46
+
47
+ def setup_logging(verbosity):
48
+ log_level = logging.DEBUG if verbosity >= 2 else logging.INFO if verbosity == 1 else logging.CRITICAL
49
+ datefmt = '%Y-%m-%d %H:%M:%S'
50
+ format_string = '%(asctime)s - %(levelname)s - %(module)s.%(funcName)s - %(message)s'
51
+ formatter = logging.Formatter(format_string, datefmt=datefmt)
52
+ console_handler = logging.StreamHandler()
53
+ console_handler.setFormatter(formatter)
54
+ console_handler.setLevel(log_level)
55
+ logging.basicConfig(level=log_level, handlers=[console_handler])
56
+
57
+
58
+ def main():
59
+ start = datetime.datetime.now()
60
+
61
+ args = parse_arguments()
62
+ setup_logging(args.verbose)
63
+
64
+ logger = logging.getLogger(__name__)
65
+
66
+ logger.debug(f"{__file__}")
67
+ logger.info(f"Start time: {start}")
68
+
69
+ logger.debug(f"Working directory = {os.getcwd()}")
70
+
71
+ example = next(e for e in Examples if e.short_name == args.example)
72
+ if example is None:
73
+ raise ValueError(f"Example not found: {args.example}")
74
+ if not args.output:
75
+ logger.debug("No output path specified, using current directory.")
76
+
77
+ logger.info(f"Copying example: {example} to {args.output}")
78
+
79
+ with ir.path(musica.examples, example.path) as example_path:
80
+ logger.info(f"Copying example from {example_path} to {args.output}")
81
+ shutil.copy(example_path, args.output[0] if args.output and len(args.output) > 0 else '.')
82
+
83
+ end = datetime.datetime.now()
84
+ logger.info(f"End time: {end}")
85
+ logger.info(f"Elapsed time: {end - start} seconds")
86
+
87
+
88
+ if __name__ == "__main__":
89
+ main()
@@ -0,0 +1 @@
1
+ from .mechanism_configuration import *
@@ -0,0 +1,274 @@
1
+ from .utils import _add_other_properties
2
+ from .reactions import ReactionComponentSerializer
3
+ from .species import Species
4
+ from .phase import Phase
5
+ from typing import Optional, Any, Dict, List, Union, Tuple
6
+ from .. import backend
7
+
8
+ _backend = backend.get_backend()
9
+ _AqueousEquilibrium = _backend._mechanism_configuration._AqueousEquilibrium
10
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
11
+ ReactionType = _backend._mechanism_configuration._ReactionType
12
+
13
+
14
+ class AqueousEquilibrium:
15
+ """
16
+ A class representing an aqueous equilibrium reaction rate constant.
17
+
18
+ Attributes:
19
+ name (str): The name of the aqueous equilibrium reaction rate constant.
20
+ condensed_phase (Phase): The condensed phase in which the reaction occurs.
21
+ condensed_phase_water (Species): The water species in the condensed phase.
22
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
23
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
24
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1].
25
+ C (float): Exponential term [K-1].
26
+ k_reverse (float): Reverse rate constant [(mol m-3)^(n-1)s-1].
27
+ other_properties (Dict[str, Any]): A dictionary of other properties of the aqueous equilibrium reaction rate constant.
28
+ """
29
+
30
+ def __init__(
31
+ self,
32
+ name: Optional[str] = None,
33
+ condensed_phase: Optional[Phase] = None,
34
+ condensed_phase_water: Optional[Species] = None,
35
+ reactants: Optional[List[Union[Species,
36
+ Tuple[float, Species]]]] = None,
37
+ products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
38
+ A: Optional[float] = None,
39
+ C: Optional[float] = None,
40
+ k_reverse: Optional[float] = None,
41
+ other_properties: Optional[Dict[str, Any]] = None,
42
+ ):
43
+ """
44
+ Initializes the AqueousEquilibrium object with the given parameters.
45
+
46
+ Args:
47
+ name (str): The name of the aqueous equilibrium reaction rate constant.
48
+ condensed_phase (Phase): The condensed phase in which the reaction occurs.
49
+ condensed_phase_water (Species): The water species in the condensed phase.
50
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
51
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
52
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1].
53
+ C (float): Exponential term [K-1].
54
+ k_reverse (float): Reverse rate constant [(mol m-3)^(n-1)s-1].
55
+ other_properties (Dict[str, Any]): A dictionary of other properties of the aqueous equilibrium reaction rate constant.
56
+ """
57
+ # Create the internal C++ instance
58
+ self._instance = _AqueousEquilibrium()
59
+
60
+ # Set all parameters
61
+ if name is not None:
62
+ self.name = name
63
+ if condensed_phase is not None:
64
+ self.condensed_phase = condensed_phase
65
+ if condensed_phase_water is not None:
66
+ self.condensed_phase_water = condensed_phase_water
67
+ if reactants is not None:
68
+ self.reactants = reactants
69
+ if products is not None:
70
+ self.products = products
71
+ if A is not None:
72
+ self.A = A
73
+ if C is not None:
74
+ self.C = C
75
+ if k_reverse is not None:
76
+ self.k_reverse = k_reverse
77
+ if other_properties is not None:
78
+ self.other_properties = other_properties
79
+
80
+ # Property delegation to self._instance
81
+ @property
82
+ def name(self) -> str:
83
+ """Get the name of the aqueous equilibrium reaction rate constant."""
84
+ return self._instance.name
85
+
86
+ @name.setter
87
+ def name(self, value: str):
88
+ """Set the name of the aqueous equilibrium reaction rate constant."""
89
+ self._instance.name = value
90
+
91
+ @property
92
+ def condensed_phase(self) -> str:
93
+ """Get the condensed phase name."""
94
+ return self._instance.condensed_phase
95
+
96
+ @condensed_phase.setter
97
+ def condensed_phase(self, value: Union[Phase, str]):
98
+ """Set the condensed phase."""
99
+ if isinstance(value, Phase):
100
+ self._instance.condensed_phase = value.name
101
+ elif isinstance(value, str):
102
+ self._instance.condensed_phase = value
103
+ else:
104
+ raise ValueError(f"Invalid condensed_phase type: {type(value)}")
105
+
106
+ @property
107
+ def condensed_phase_water(self) -> str:
108
+ """Get the condensed phase water species name."""
109
+ return self._instance.condensed_phase_water
110
+
111
+ @condensed_phase_water.setter
112
+ def condensed_phase_water(self, value: Union[Species, str]):
113
+ """Set the condensed phase water species."""
114
+ if isinstance(value, Species):
115
+ self._instance.condensed_phase_water = value.name
116
+ elif isinstance(value, str):
117
+ self._instance.condensed_phase_water = value
118
+ else:
119
+ raise ValueError(f"Invalid condensed_phase_water type: {type(value)}")
120
+
121
+ @property
122
+ def reactants(self) -> List[Union[Species, Tuple[float, Species]]]:
123
+ """Get the reactants as Python objects."""
124
+ # Convert from C++ _ReactionComponent objects to Python Species objects
125
+ result = []
126
+ for rc in self._instance.reactants:
127
+ if hasattr(rc, 'coefficient') and rc.coefficient != 1.0:
128
+ # Create a tuple with coefficient and species
129
+ species = Species(name=rc.species_name)
130
+ result.append((rc.coefficient, species))
131
+ else:
132
+ # Just the species
133
+ species = Species(name=rc.species_name)
134
+ result.append(species)
135
+ return result
136
+
137
+ @reactants.setter
138
+ def reactants(self, value: List[Union[Species, Tuple[float, Species]]]):
139
+ """Set the reactants, converting from Python to C++ objects."""
140
+ cpp_reactants = []
141
+ for r in value:
142
+ if isinstance(r, Species):
143
+ cpp_reactants.append(_ReactionComponent(r.name))
144
+ elif isinstance(r, tuple) and len(r) == 2:
145
+ coefficient, species = r
146
+ cpp_reactants.append(_ReactionComponent(species.name, coefficient))
147
+ else:
148
+ raise ValueError(f"Invalid reactant format: {r}")
149
+ self._instance.reactants = cpp_reactants
150
+
151
+ @property
152
+ def products(self) -> List[Union[Species, Tuple[float, Species]]]:
153
+ """Get the products as Python objects."""
154
+ # Convert from C++ _ReactionComponent objects to Python Species objects
155
+ result = []
156
+ for rc in self._instance.products:
157
+ if hasattr(rc, 'coefficient') and rc.coefficient != 1.0:
158
+ # Create a tuple with coefficient and species
159
+ species = Species(name=rc.species_name)
160
+ result.append((rc.coefficient, species))
161
+ else:
162
+ # Just the species
163
+ species = Species(name=rc.species_name)
164
+ result.append(species)
165
+ return result
166
+
167
+ @products.setter
168
+ def products(self, value: List[Union[Species, Tuple[float, Species]]]):
169
+ """Set the products, converting from Python to C++ objects."""
170
+ cpp_products = []
171
+ for p in value:
172
+ if isinstance(p, Species):
173
+ cpp_products.append(_ReactionComponent(p.name))
174
+ elif isinstance(p, tuple) and len(p) == 2:
175
+ coefficient, species = p
176
+ cpp_products.append(_ReactionComponent(species.name, coefficient))
177
+ else:
178
+ raise ValueError(f"Invalid product format: {p}")
179
+ self._instance.products = cpp_products
180
+
181
+ @property
182
+ def A(self) -> float:
183
+ """Get the pre-exponential factor."""
184
+ return self._instance.A
185
+
186
+ @A.setter
187
+ def A(self, value: float):
188
+ """Set the pre-exponential factor."""
189
+ self._instance.A = value
190
+
191
+ @property
192
+ def C(self) -> float:
193
+ """Get the exponential term."""
194
+ return self._instance.C
195
+
196
+ @C.setter
197
+ def C(self, value: float):
198
+ """Set the exponential term."""
199
+ self._instance.C = value
200
+
201
+ @property
202
+ def k_reverse(self) -> float:
203
+ """Get the reverse rate constant."""
204
+ return self._instance.k_reverse
205
+
206
+ @k_reverse.setter
207
+ def k_reverse(self, value: float):
208
+ """Set the reverse rate constant."""
209
+ self._instance.k_reverse = value
210
+
211
+ @property
212
+ def other_properties(self) -> Dict[str, Any]:
213
+ """Get the other properties."""
214
+ return self._instance.other_properties
215
+
216
+ @other_properties.setter
217
+ def other_properties(self, value: Dict[str, Any]):
218
+ """Set the other properties."""
219
+ self._instance.other_properties = value
220
+
221
+ @property
222
+ def type(self):
223
+ """Get the reaction type."""
224
+ return ReactionType.AqueousEquilibrium
225
+
226
+ def _create_serialize_dict(self, instance) -> Dict:
227
+ """
228
+ Helper method to create the serialization dictionary.
229
+
230
+ Args:
231
+ instance: The instance to serialize (either self._instance or a _AqueousEquilibrium object).
232
+
233
+ Returns:
234
+ Dict: Base serialization dictionary.
235
+ """
236
+ return {
237
+ "type": "AQUEOUS_EQUILIBRIUM",
238
+ "name": instance.name,
239
+ "condensed phase": instance.condensed_phase,
240
+ "condensed-phase water": instance.condensed_phase_water,
241
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(instance.reactants),
242
+ "products": ReactionComponentSerializer.serialize_list_reaction_components(instance.products),
243
+ "A": instance.A,
244
+ "C": instance.C,
245
+ "k_reverse": instance.k_reverse,
246
+ }
247
+
248
+ def serialize(self) -> Dict:
249
+ """
250
+ Serialize the AqueousEquilibrium object to a dictionary using only Python-visible data.
251
+
252
+ Returns:
253
+ Dict: A dictionary representation of the AqueousEquilibrium object.
254
+ """
255
+ serialize_dict = self._create_serialize_dict(self._instance)
256
+ _add_other_properties(serialize_dict, self.other_properties)
257
+ return serialize_dict
258
+
259
+ @staticmethod
260
+ def serialize_static(instance) -> Dict:
261
+ """
262
+ Static serialize method for compatibility with C++ _AqueousEquilibrium objects.
263
+
264
+ Args:
265
+ instance: The _AqueousEquilibrium instance to serialize.
266
+
267
+ Returns:
268
+ Dict: A dictionary representation of the AqueousEquilibrium object.
269
+ """
270
+ # Create a temporary AqueousEquilibrium object to use the helper method
271
+ temp_aqueous_equilibrium = AqueousEquilibrium()
272
+ serialize_dict = temp_aqueous_equilibrium._create_serialize_dict(instance)
273
+ _add_other_properties(serialize_dict, instance.other_properties)
274
+ return serialize_dict
@@ -0,0 +1,307 @@
1
+ from typing import Optional, Any, Dict, List, Union, Tuple
2
+ from .. import backend
3
+ from .phase import Phase
4
+ from .species import Species
5
+ from .reactions import ReactionComponentSerializer
6
+ from .utils import _add_other_properties
7
+ from ..constants import BOLTZMANN
8
+
9
+ _backend = backend.get_backend()
10
+ _Arrhenius = _backend._mechanism_configuration._Arrhenius
11
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
12
+ ReactionType = _backend._mechanism_configuration._ReactionType
13
+
14
+
15
+ class Arrhenius:
16
+ """
17
+ A class representing an Arrhenius rate constant.
18
+
19
+ k = A * exp( C / T ) * ( T / D )^B * exp( 1 - E * P )
20
+
21
+ where:
22
+ k = rate constant
23
+ A = pre-exponential factor [(mol m-3)^(n-1)s-1]
24
+ B = temperature exponent [unitless]
25
+ C = exponential term [K-1]
26
+ D = reference temperature [K]
27
+ E = pressure scaling term [Pa-1]
28
+ T = temperature [K]
29
+ P = pressure [Pa]
30
+ n = number of reactants
31
+
32
+ Attributes:
33
+ name (str): The name of the Arrhenius rate constant.
34
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1] where n is the number of reactants.
35
+ B (float): Temperature exponent [unitless].
36
+ C (float): Exponential term [K-1].
37
+ D (float): Reference Temperature [K].
38
+ E (float): Pressure scaling term [Pa-1].
39
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
40
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
41
+ gas_phase (Phase): The gas phase in which the reaction occurs.
42
+ other_properties (Dict[str, Any]): A dictionary of other properties of the Arrhenius rate constant.
43
+ """
44
+
45
+ def __init__(
46
+ self,
47
+ name: Optional[str] = None,
48
+ A: Optional[float] = None,
49
+ B: Optional[float] = None,
50
+ C: Optional[float] = None,
51
+ Ea: Optional[float] = None,
52
+ D: Optional[float] = None,
53
+ E: Optional[float] = None,
54
+ reactants: Optional[List[Union[Species,
55
+ Tuple[float, Species]]]] = None,
56
+ products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
57
+ gas_phase: Optional[Phase] = None,
58
+ other_properties: Optional[Dict[str, Any]] = None,
59
+ ):
60
+ """
61
+ Initializes the Arrhenius object with the given parameters.
62
+
63
+ Args:
64
+ name (str): The name of the Arrhenius rate constant.
65
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1] where n is the number of reactants.
66
+ B (float): Temperature exponent [unitless].
67
+ C (float): Exponential term [K-1].
68
+ Ea (float): Activation energy [J molecule-1].
69
+ D (float): Reference Temperature [K].
70
+ E (float): Pressure scaling term [Pa-1].
71
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
72
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
73
+ gas_phase (Phase): The gas phase in which the reaction occurs.
74
+ other_properties (Dict[str, Any]): A dictionary of other properties of the Arrhenius rate constant.
75
+ """
76
+ # Create the internal C++ instance
77
+ self._instance = _Arrhenius()
78
+
79
+ # Validate mutually exclusive parameters
80
+ if C is not None and Ea is not None:
81
+ raise ValueError("Cannot specify both C and Ea.")
82
+
83
+ # Set all parameters
84
+ if name is not None:
85
+ self.name = name
86
+ if A is not None:
87
+ self.A = A
88
+ if B is not None:
89
+ self.B = B
90
+ if Ea is not None:
91
+ self.C = -Ea / BOLTZMANN
92
+ elif C is not None:
93
+ self.C = C
94
+ if D is not None:
95
+ self.D = D
96
+ if E is not None:
97
+ self.E = E
98
+ if reactants is not None:
99
+ self.reactants = reactants
100
+ if products is not None:
101
+ self.products = products
102
+ if gas_phase is not None:
103
+ self.gas_phase = gas_phase
104
+ if other_properties is not None:
105
+ self.other_properties = other_properties
106
+
107
+ # Property delegation to self._instance
108
+ @property
109
+ def name(self) -> str:
110
+ """Get the name of the Arrhenius rate constant."""
111
+ return self._instance.name
112
+
113
+ @name.setter
114
+ def name(self, value: str):
115
+ """Set the name of the Arrhenius rate constant."""
116
+ self._instance.name = value
117
+
118
+ @property
119
+ def A(self) -> float:
120
+ """Get the pre-exponential factor."""
121
+ return self._instance.A
122
+
123
+ @A.setter
124
+ def A(self, value: float):
125
+ """Set the pre-exponential factor."""
126
+ self._instance.A = value
127
+
128
+ @property
129
+ def B(self) -> float:
130
+ """Get the temperature exponent."""
131
+ return self._instance.B
132
+
133
+ @B.setter
134
+ def B(self, value: float):
135
+ """Set the temperature exponent."""
136
+ self._instance.B = value
137
+
138
+ @property
139
+ def C(self) -> float:
140
+ """Get the exponential term."""
141
+ return self._instance.C
142
+
143
+ @C.setter
144
+ def C(self, value: float):
145
+ """Set the exponential term."""
146
+ self._instance.C = value
147
+
148
+ @property
149
+ def D(self) -> float:
150
+ """Get the reference temperature."""
151
+ return self._instance.D
152
+
153
+ @D.setter
154
+ def D(self, value: float):
155
+ """Set the reference temperature."""
156
+ self._instance.D = value
157
+
158
+ @property
159
+ def E(self) -> float:
160
+ """Get the pressure scaling term."""
161
+ return self._instance.E
162
+
163
+ @E.setter
164
+ def E(self, value: float):
165
+ """Set the pressure scaling term."""
166
+ self._instance.E = value
167
+
168
+ @property
169
+ def reactants(self) -> List[Union[Species, Tuple[float, Species]]]:
170
+ """Get the reactants as Python objects."""
171
+ # Convert from C++ _ReactionComponent objects to Python Species objects
172
+ result = []
173
+ for rc in self._instance.reactants:
174
+ if hasattr(rc, 'coefficient') and rc.coefficient != 1.0:
175
+ # Create a tuple with coefficient and species
176
+ species = Species(name=rc.species_name)
177
+ result.append((rc.coefficient, species))
178
+ else:
179
+ # Just the species
180
+ species = Species(name=rc.species_name)
181
+ result.append(species)
182
+ return result
183
+
184
+ @reactants.setter
185
+ def reactants(self, value: List[Union[Species, Tuple[float, Species]]]):
186
+ """Set the reactants, converting from Python to C++ objects."""
187
+ cpp_reactants = []
188
+ for r in value:
189
+ if isinstance(r, Species):
190
+ cpp_reactants.append(_ReactionComponent(r.name))
191
+ elif isinstance(r, tuple) and len(r) == 2:
192
+ coefficient, species = r
193
+ cpp_reactants.append(_ReactionComponent(species.name, coefficient))
194
+ else:
195
+ raise ValueError(f"Invalid reactant format: {r}")
196
+ self._instance.reactants = cpp_reactants
197
+
198
+ @property
199
+ def products(self) -> List[Union[Species, Tuple[float, Species]]]:
200
+ """Get the products as Python objects."""
201
+ # Convert from C++ _ReactionComponent objects to Python Species objects
202
+ result = []
203
+ for rc in self._instance.products:
204
+ if hasattr(rc, 'coefficient') and rc.coefficient != 1.0:
205
+ # Create a tuple with coefficient and species
206
+ species = Species(name=rc.species_name)
207
+ result.append((rc.coefficient, species))
208
+ else:
209
+ # Just the species
210
+ species = Species(name=rc.species_name)
211
+ result.append(species)
212
+ return result
213
+
214
+ @products.setter
215
+ def products(self, value: List[Union[Species, Tuple[float, Species]]]):
216
+ """Set the products, converting from Python to C++ objects."""
217
+ cpp_products = []
218
+ for p in value:
219
+ if isinstance(p, Species):
220
+ cpp_products.append(_ReactionComponent(p.name))
221
+ elif isinstance(p, tuple) and len(p) == 2:
222
+ coefficient, species = p
223
+ cpp_products.append(_ReactionComponent(species.name, coefficient))
224
+ else:
225
+ raise ValueError(f"Invalid product format: {p}")
226
+ self._instance.products = cpp_products
227
+
228
+ @property
229
+ def gas_phase(self) -> str:
230
+ """Get the gas phase name."""
231
+ return self._instance.gas_phase
232
+
233
+ @gas_phase.setter
234
+ def gas_phase(self, value: Union[Phase, str]):
235
+ """Set the gas phase."""
236
+ if isinstance(value, Phase):
237
+ self._instance.gas_phase = value.name
238
+ elif isinstance(value, str):
239
+ self._instance.gas_phase = value
240
+ else:
241
+ raise ValueError(f"Invalid gas_phase type: {type(value)}")
242
+
243
+ @property
244
+ def other_properties(self) -> Dict[str, Any]:
245
+ """Get the other properties."""
246
+ return self._instance.other_properties
247
+
248
+ @other_properties.setter
249
+ def other_properties(self, value: Dict[str, Any]):
250
+ """Set the other properties."""
251
+ self._instance.other_properties = value
252
+
253
+ @property
254
+ def type(self):
255
+ """Get the reaction type."""
256
+ return ReactionType.Arrhenius
257
+
258
+ def _create_serialize_dict(self, instance) -> Dict:
259
+ """
260
+ Helper method to create the serialization dictionary.
261
+
262
+ Args:
263
+ instance: The instance to serialize (either self._instance or a _Arrhenius object).
264
+
265
+ Returns:
266
+ Dict: Base serialization dictionary.
267
+ """
268
+ return {
269
+ "type": "ARRHENIUS",
270
+ "name": instance.name,
271
+ "A": instance.A,
272
+ "B": instance.B,
273
+ "C": instance.C,
274
+ "D": instance.D,
275
+ "E": instance.E,
276
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(instance.reactants),
277
+ "products": ReactionComponentSerializer.serialize_list_reaction_components(instance.products),
278
+ "gas phase": instance.gas_phase,
279
+ }
280
+
281
+ def serialize(self) -> Dict:
282
+ """
283
+ Serialize the Arrhenius object to a dictionary using only Python-visible data.
284
+
285
+ Returns:
286
+ Dict: A dictionary representation of the Arrhenius object.
287
+ """
288
+ serialize_dict = self._create_serialize_dict(self._instance)
289
+ _add_other_properties(serialize_dict, self.other_properties)
290
+ return serialize_dict
291
+
292
+ @staticmethod
293
+ def serialize_static(instance) -> Dict:
294
+ """
295
+ Static serialize method for compatibility with C++ _Arrhenius objects.
296
+
297
+ Args:
298
+ instance: The _Arrhenius instance to serialize.
299
+
300
+ Returns:
301
+ Dict: A dictionary representation of the Arrhenius object.
302
+ """
303
+ # Create a temporary Arrhenius object to use the helper method
304
+ temp_arrhenius = Arrhenius()
305
+ serialize_dict = temp_arrhenius._create_serialize_dict(instance)
306
+ _add_other_properties(serialize_dict, instance.other_properties)
307
+ return serialize_dict