musica 0.12.2__cp311-cp311-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-311-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
@@ -0,0 +1,299 @@
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
+ _Branched = _backend._mechanism_configuration._Branched
10
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
11
+ ReactionType = _backend._mechanism_configuration._ReactionType
12
+
13
+
14
+ class Branched:
15
+ """
16
+ A class representing a branched reaction rate constant.
17
+
18
+ (TODO: get details from MusicBox)
19
+
20
+ Attributes:
21
+ name (str): The name of the branched reaction rate constant.
22
+ X (float): Pre-exponential branching factor [(mol m-3)^-(n-1)s-1].
23
+ Y (float): Exponential branching factor [K-1].
24
+ a0 (float): Z parameter [unitless].
25
+ n (float): A parameter [unitless].
26
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
27
+ nitrate_products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the nitrate branch.
28
+ alkoxy_products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the alkoxy branch.
29
+ gas_phase (Phase): The gas phase in which the reaction occurs.
30
+ other_properties (Dict[str, Any]): A dictionary of other properties of the branched reaction rate constant.
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ name: Optional[str] = None,
36
+ X: Optional[float] = None,
37
+ Y: Optional[float] = None,
38
+ a0: Optional[float] = None,
39
+ n: Optional[float] = None,
40
+ reactants: Optional[List[Union[Species,
41
+ Tuple[float, Species]]]] = None,
42
+ nitrate_products: Optional[List[Union[Species,
43
+ Tuple[float, Species]]]] = None,
44
+ alkoxy_products: Optional[List[Union[Species,
45
+ Tuple[float, Species]]]] = None,
46
+ gas_phase: Optional[Phase] = None,
47
+ other_properties: Optional[Dict[str, Any]] = None,
48
+ ):
49
+ """
50
+ Initializes the Branched object with the given parameters.
51
+
52
+ Args:
53
+ name (str): The name of the branched reaction rate constant.
54
+ X (float): Pre-exponential branching factor [(mol m-3)^-(n-1)s-1].
55
+ Y (float): Exponential branching factor [K-1].
56
+ a0 (float): Z parameter [unitless].
57
+ n (float): A parameter [unitless].
58
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
59
+ nitrate_products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the nitrate branch.
60
+ alkoxy_products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the alkoxy branch.
61
+ gas_phase (Phase): The gas phase in which the reaction occurs.
62
+ other_properties (Dict[str, Any]): A dictionary of other properties of the branched reaction rate constant.
63
+ """
64
+ # Create the internal C++ instance
65
+ self._instance = _Branched()
66
+
67
+ # Set all parameters
68
+ if name is not None:
69
+ self.name = name
70
+ if X is not None:
71
+ self.X = X
72
+ if Y is not None:
73
+ self.Y = Y
74
+ if a0 is not None:
75
+ self.a0 = a0
76
+ if n is not None:
77
+ self.n = n
78
+ if reactants is not None:
79
+ self.reactants = reactants
80
+ if nitrate_products is not None:
81
+ self.nitrate_products = nitrate_products
82
+ if alkoxy_products is not None:
83
+ self.alkoxy_products = alkoxy_products
84
+ if gas_phase is not None:
85
+ self.gas_phase = gas_phase
86
+ if other_properties is not None:
87
+ self.other_properties = other_properties
88
+
89
+ # Property delegation to self._instance
90
+ @property
91
+ def name(self) -> str:
92
+ """Get the name of the branched reaction rate constant."""
93
+ return self._instance.name
94
+
95
+ @name.setter
96
+ def name(self, value: str):
97
+ """Set the name of the branched reaction rate constant."""
98
+ self._instance.name = value
99
+
100
+ @property
101
+ def X(self) -> float:
102
+ """Get the pre-exponential branching factor."""
103
+ return self._instance.X
104
+
105
+ @X.setter
106
+ def X(self, value: float):
107
+ """Set the pre-exponential branching factor."""
108
+ self._instance.X = value
109
+
110
+ @property
111
+ def Y(self) -> float:
112
+ """Get the exponential branching factor."""
113
+ return self._instance.Y
114
+
115
+ @Y.setter
116
+ def Y(self, value: float):
117
+ """Set the exponential branching factor."""
118
+ self._instance.Y = value
119
+
120
+ @property
121
+ def a0(self) -> float:
122
+ """Get the Z parameter."""
123
+ return self._instance.a0
124
+
125
+ @a0.setter
126
+ def a0(self, value: float):
127
+ """Set the Z parameter."""
128
+ self._instance.a0 = value
129
+
130
+ @property
131
+ def n(self) -> float:
132
+ """Get the A parameter."""
133
+ return self._instance.n
134
+
135
+ @n.setter
136
+ def n(self, value: float):
137
+ """Set the A parameter."""
138
+ self._instance.n = value
139
+
140
+ @property
141
+ def reactants(self) -> List[Union[Species, Tuple[float, Species]]]:
142
+ """Get the reactants as Python objects."""
143
+ # Convert from C++ _ReactionComponent objects to Python Species objects
144
+ result = []
145
+ for rc in self._instance.reactants:
146
+ if hasattr(rc, 'coefficient') and rc.coefficient != 1.0:
147
+ # Create a tuple with coefficient and species
148
+ species = Species(name=rc.species_name)
149
+ result.append((rc.coefficient, species))
150
+ else:
151
+ # Just the species
152
+ species = Species(name=rc.species_name)
153
+ result.append(species)
154
+ return result
155
+
156
+ @reactants.setter
157
+ def reactants(self, value: List[Union[Species, Tuple[float, Species]]]):
158
+ """Set the reactants, converting from Python to C++ objects."""
159
+ cpp_reactants = []
160
+ for r in value:
161
+ if isinstance(r, Species):
162
+ cpp_reactants.append(_ReactionComponent(r.name))
163
+ elif isinstance(r, tuple) and len(r) == 2:
164
+ coefficient, species = r
165
+ cpp_reactants.append(_ReactionComponent(species.name, coefficient))
166
+ else:
167
+ raise ValueError(f"Invalid reactant format: {r}")
168
+ self._instance.reactants = cpp_reactants
169
+
170
+ @property
171
+ def nitrate_products(self) -> List[Union[Species, Tuple[float, Species]]]:
172
+ """Get the nitrate products as Python objects."""
173
+ # Convert from C++ _ReactionComponent objects to Python Species objects
174
+ result = []
175
+ for rc in self._instance.nitrate_products:
176
+ if hasattr(rc, 'coefficient') and rc.coefficient != 1.0:
177
+ # Create a tuple with coefficient and species
178
+ species = Species(name=rc.species_name)
179
+ result.append((rc.coefficient, species))
180
+ else:
181
+ # Just the species
182
+ species = Species(name=rc.species_name)
183
+ result.append(species)
184
+ return result
185
+
186
+ @nitrate_products.setter
187
+ def nitrate_products(self, value: List[Union[Species, Tuple[float, Species]]]):
188
+ """Set the nitrate products, converting from Python to C++ objects."""
189
+ cpp_products = []
190
+ for p in value:
191
+ if isinstance(p, Species):
192
+ cpp_products.append(_ReactionComponent(p.name))
193
+ elif isinstance(p, tuple) and len(p) == 2:
194
+ coefficient, species = p
195
+ cpp_products.append(_ReactionComponent(species.name, coefficient))
196
+ else:
197
+ raise ValueError(f"Invalid nitrate product format: {p}")
198
+ self._instance.nitrate_products = cpp_products
199
+
200
+ @property
201
+ def alkoxy_products(self) -> List[Union[Species, Tuple[float, Species]]]:
202
+ """Get the alkoxy products as Python objects."""
203
+ # Convert from C++ _ReactionComponent objects to Python Species objects
204
+ result = []
205
+ for rc in self._instance.alkoxy_products:
206
+ if hasattr(rc, 'coefficient') and rc.coefficient != 1.0:
207
+ # Create a tuple with coefficient and species
208
+ species = Species(name=rc.species_name)
209
+ result.append((rc.coefficient, species))
210
+ else:
211
+ # Just the species
212
+ species = Species(name=rc.species_name)
213
+ result.append(species)
214
+ return result
215
+
216
+ @alkoxy_products.setter
217
+ def alkoxy_products(self, value: List[Union[Species, Tuple[float, Species]]]):
218
+ """Set the alkoxy products, converting from Python to C++ objects."""
219
+ cpp_products = []
220
+ for p in value:
221
+ if isinstance(p, Species):
222
+ cpp_products.append(_ReactionComponent(p.name))
223
+ elif isinstance(p, tuple) and len(p) == 2:
224
+ coefficient, species = p
225
+ cpp_products.append(_ReactionComponent(species.name, coefficient))
226
+ else:
227
+ raise ValueError(f"Invalid alkoxy product format: {p}")
228
+ self._instance.alkoxy_products = cpp_products
229
+
230
+ @property
231
+ def gas_phase(self) -> str:
232
+ """Get the gas phase name."""
233
+ return self._instance.gas_phase
234
+
235
+ @gas_phase.setter
236
+ def gas_phase(self, value: Union[Phase, str]):
237
+ """Set the gas phase."""
238
+ if isinstance(value, Phase):
239
+ self._instance.gas_phase = value.name
240
+ elif isinstance(value, str):
241
+ self._instance.gas_phase = value
242
+ else:
243
+ raise ValueError(f"Invalid gas_phase type: {type(value)}")
244
+
245
+ @property
246
+ def other_properties(self) -> Dict[str, Any]:
247
+ """Get the other properties."""
248
+ return self._instance.other_properties
249
+
250
+ @other_properties.setter
251
+ def other_properties(self, value: Dict[str, Any]):
252
+ """Set the other properties."""
253
+ self._instance.other_properties = value
254
+
255
+ @property
256
+ def type(self):
257
+ """Get the reaction type."""
258
+ return ReactionType.Branched
259
+
260
+ def serialize(self) -> Dict:
261
+ """
262
+ Serialize the Branched object to a dictionary using only Python-visible data.
263
+
264
+ Returns:
265
+ Dict: A dictionary representation of the Branched object.
266
+ """
267
+ serialize_dict = {
268
+ "type": "BRANCHED_NO_RO2",
269
+ "name": self.name,
270
+ "X": self.X,
271
+ "Y": self.Y,
272
+ "a0": self.a0,
273
+ "n": self.n,
274
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(
275
+ self._instance.reactants),
276
+ "nitrate products": ReactionComponentSerializer.serialize_list_reaction_components(
277
+ self._instance.nitrate_products),
278
+ "alkoxy products": ReactionComponentSerializer.serialize_list_reaction_components(
279
+ self._instance.alkoxy_products),
280
+ "gas phase": self.gas_phase,
281
+ }
282
+ _add_other_properties(serialize_dict, self.other_properties)
283
+ return serialize_dict
284
+
285
+ @staticmethod
286
+ def serialize_static(instance) -> Dict:
287
+ """
288
+ Static serialize method for compatibility with C++ _Branched objects.
289
+
290
+ Args:
291
+ instance: The _Branched instance to serialize.
292
+
293
+ Returns:
294
+ Dict: A dictionary representation of the Branched object.
295
+ """
296
+ # Create a temporary Branched object and use its instance serialize method
297
+ temp_branched = Branched()
298
+ temp_branched._instance = instance
299
+ return temp_branched.serialize()
@@ -0,0 +1,309 @@
1
+ from ..constants import BOLTZMANN
2
+ from .utils import _add_other_properties
3
+ from .reactions import ReactionComponentSerializer
4
+ from .species import Species
5
+ from .phase import Phase
6
+ from typing import Optional, Any, Dict, List, Union, Tuple
7
+ from .. import backend
8
+
9
+ _backend = backend.get_backend()
10
+ _CondensedPhaseArrhenius = _backend._mechanism_configuration._CondensedPhaseArrhenius
11
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
12
+
13
+
14
+ class CondensedPhaseArrhenius:
15
+ """
16
+ A class representing a condensed phase Arrhenius rate constant.
17
+
18
+ Attributes:
19
+ name (str): The name of the condensed phase Arrhenius rate constant.
20
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1].
21
+ B (float): Temperature exponent [unitless].
22
+ C (float): Exponential term [K-1].
23
+ Ea (float): Activation energy [J molecule-1].
24
+ D (float): Reference Temperature [K].
25
+ E (float): Pressure scaling term [Pa-1].
26
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
27
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
28
+ condensed_phase (Phase): The condensed phase in which the reaction occurs.
29
+ other_properties (Dict[str, Any]): A dictionary of other properties of the condensed phase Arrhenius rate constant.
30
+ """
31
+
32
+ def __init__(
33
+ self,
34
+ name: Optional[str] = None,
35
+ A: Optional[float] = None,
36
+ B: Optional[float] = None,
37
+ C: Optional[float] = None,
38
+ Ea: Optional[float] = None,
39
+ D: Optional[float] = None,
40
+ E: Optional[float] = None,
41
+ reactants: Optional[List[Union[Species,
42
+ Tuple[float, Species]]]] = None,
43
+ products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
44
+ condensed_phase: Optional[Phase] = None,
45
+ other_properties: Optional[Dict[str, Any]] = None,
46
+ ):
47
+ """
48
+ Initializes the CondensedPhaseArrhenius object with the given parameters.
49
+
50
+ Args:
51
+ name (str): The name of the condensed phase Arrhenius rate constant.
52
+ A (float): Pre-exponential factor [(mol m-3)^(n-1)s-1].
53
+ B (float): Temperature exponent [unitless].
54
+ C (float): Exponential term [K-1].
55
+ Ea (float): Activation energy [J molecule-1].
56
+ D (float): Reference Temperature [K].
57
+ E (float): Pressure scaling term [Pa-1].
58
+ reactants (List[Union[Species, Tuple[float, Species]]]]: A list of reactants involved in the reaction.
59
+ products (List[Union[Species, Tuple[float, Species]]]]: A list of products formed in the reaction.
60
+ condensed_phase (Phase): The condensed phase in which the reaction occurs.
61
+ other_properties (Dict[str, Any]): A dictionary of other properties of the condensed phase Arrhenius rate constant.
62
+ """
63
+ # Create the internal C++ instance
64
+ self._instance = _CondensedPhaseArrhenius()
65
+
66
+ # Store Python objects for reactants, products, phases
67
+ self._reactants = reactants if reactants is not None else []
68
+ self._products = products if products is not None else []
69
+ self._condensed_phase = condensed_phase
70
+ self._other_properties = other_properties if other_properties is not None else {}
71
+
72
+ # Set basic properties on the C++ instance
73
+ if name is not None:
74
+ self._instance.name = name
75
+ if A is not None:
76
+ self._instance.A = A
77
+ if B is not None:
78
+ self._instance.B = B
79
+ if C is not None and Ea is not None:
80
+ raise ValueError("Cannot specify both C and Ea.")
81
+ if Ea is not None:
82
+ self._instance.C = -Ea / BOLTZMANN
83
+ elif C is not None:
84
+ self._instance.C = C
85
+ if D is not None:
86
+ self._instance.D = D
87
+ if E is not None:
88
+ self._instance.E = E
89
+
90
+ # Set reactants on the C++ instance
91
+ if reactants is not None:
92
+ self._instance.reactants = [
93
+ (
94
+ _ReactionComponent(r.name)
95
+ if isinstance(r, Species)
96
+ else _ReactionComponent(r[1].name, r[0])
97
+ )
98
+ for r in reactants
99
+ ]
100
+
101
+ # Set products on the C++ instance
102
+ if products is not None:
103
+ self._instance.products = [
104
+ (
105
+ _ReactionComponent(p.name)
106
+ if isinstance(p, Species)
107
+ else _ReactionComponent(p[1].name, p[0])
108
+ )
109
+ for p in products
110
+ ]
111
+
112
+ # Set phase information on the C++ instance
113
+ if condensed_phase is not None:
114
+ self._instance.condensed_phase = condensed_phase.name
115
+ if other_properties is not None:
116
+ self._instance.other_properties = other_properties
117
+
118
+ def __getattr__(self, name):
119
+ """Delegate unknown attribute access to the internal instance."""
120
+ return getattr(self._instance, name)
121
+
122
+ @property
123
+ def type(self):
124
+ """The reaction type."""
125
+ return self._instance.type
126
+
127
+ @property
128
+ def name(self) -> str:
129
+ """The name of the condensed phase Arrhenius rate constant."""
130
+ return self._instance.name
131
+
132
+ @name.setter
133
+ def name(self, value: str):
134
+ self._instance.name = value
135
+
136
+ @property
137
+ def A(self) -> float:
138
+ """Pre-exponential factor [(mol m-3)^(n-1)s-1]."""
139
+ return self._instance.A
140
+
141
+ @A.setter
142
+ def A(self, value: float):
143
+ self._instance.A = value
144
+
145
+ @property
146
+ def B(self) -> float:
147
+ """Temperature exponent [unitless]."""
148
+ return self._instance.B
149
+
150
+ @B.setter
151
+ def B(self, value: float):
152
+ self._instance.B = value
153
+
154
+ @property
155
+ def C(self) -> float:
156
+ """Exponential term [K-1]."""
157
+ return self._instance.C
158
+
159
+ @C.setter
160
+ def C(self, value: float):
161
+ self._instance.C = value
162
+
163
+ @property
164
+ def D(self) -> float:
165
+ """Reference Temperature [K]."""
166
+ return self._instance.D
167
+
168
+ @D.setter
169
+ def D(self, value: float):
170
+ self._instance.D = value
171
+
172
+ @property
173
+ def E(self) -> float:
174
+ """Pressure scaling term [Pa-1]."""
175
+ return self._instance.E
176
+
177
+ @E.setter
178
+ def E(self, value: float):
179
+ self._instance.E = value
180
+
181
+ @property
182
+ def reactants(self) -> List[Union[Species, Tuple[float, Species]]]:
183
+ """A list of reactants involved in the reaction."""
184
+ return self._reactants
185
+
186
+ @reactants.setter
187
+ def reactants(self, value: List[Union[Species, Tuple[float, Species]]]):
188
+ self._reactants = value
189
+ # Update the C++ instance
190
+ self._instance.reactants = [
191
+ (
192
+ _ReactionComponent(r.name)
193
+ if isinstance(r, Species)
194
+ else _ReactionComponent(r[1].name, r[0])
195
+ )
196
+ for r in value
197
+ ]
198
+
199
+ @property
200
+ def products(self) -> List[Union[Species, Tuple[float, Species]]]:
201
+ """A list of products formed in the reaction."""
202
+ return self._products
203
+
204
+ @products.setter
205
+ def products(self, value: List[Union[Species, Tuple[float, Species]]]):
206
+ self._products = value
207
+ # Update the C++ instance
208
+ self._instance.products = [
209
+ (
210
+ _ReactionComponent(p.name)
211
+ if isinstance(p, Species)
212
+ else _ReactionComponent(p[1].name, p[0])
213
+ )
214
+ for p in value
215
+ ]
216
+
217
+ @property
218
+ def condensed_phase(self) -> Phase:
219
+ """The condensed phase in which the reaction occurs."""
220
+ return self._condensed_phase
221
+
222
+ @condensed_phase.setter
223
+ def condensed_phase(self, value: Phase):
224
+ self._condensed_phase = value
225
+ # Update the C++ instance
226
+ self._instance.condensed_phase = value.name if value is not None else ""
227
+
228
+ @property
229
+ def other_properties(self) -> Dict[str, Any]:
230
+ """A dictionary of other properties of the condensed phase Arrhenius rate constant."""
231
+ return self._other_properties
232
+
233
+ @other_properties.setter
234
+ def other_properties(self, value: Dict[str, Any]):
235
+ self._other_properties = value
236
+ # Update the C++ instance
237
+ self._instance.other_properties = value
238
+
239
+ def serialize(self) -> Dict:
240
+ """
241
+ Serialize the CondensedPhaseArrhenius instance to a dictionary.
242
+
243
+ Returns:
244
+ Dict: A dictionary representation of the condensed phase Arrhenius rate constant.
245
+ """
246
+ # Convert Python reactants/products to serializable format
247
+ def serialize_python_components(components):
248
+ result = []
249
+ for component in components:
250
+ if isinstance(component, Species):
251
+ result.append(component.name)
252
+ elif isinstance(component, tuple) and len(component) == 2:
253
+ # Handle (coefficient, Species) tuples
254
+ coefficient, species = component
255
+ result.append({
256
+ "species name": species.name,
257
+ "coefficient": coefficient
258
+ })
259
+ else:
260
+ # Fallback: treat as Species
261
+ result.append(component.name if hasattr(component, 'name') else str(component))
262
+ return result
263
+
264
+ serialize_dict = {
265
+ "type": "CONDENSED_PHASE_ARRHENIUS",
266
+ "name": self.name,
267
+ "A": self.A,
268
+ "B": self.B,
269
+ "C": self.C,
270
+ "D": self.D,
271
+ "E": self.E,
272
+ "reactants": serialize_python_components(self._reactants),
273
+ "products": serialize_python_components(self._products),
274
+ "condensed phase": self._condensed_phase.name if self._condensed_phase is not None else "",
275
+ }
276
+ _add_other_properties(serialize_dict, self._other_properties)
277
+ return serialize_dict
278
+
279
+ @staticmethod
280
+ def serialize_static(instance) -> Dict:
281
+ """
282
+ Static serialize method for backward compatibility.
283
+
284
+ Args:
285
+ instance: The CondensedPhaseArrhenius instance to serialize (can be Python wrapper or C++ type).
286
+
287
+ Returns:
288
+ Dict: A dictionary representation of the condensed phase Arrhenius rate constant.
289
+ """
290
+ # Check if it's the new composition-based Python wrapper
291
+ if hasattr(instance, '_instance'):
292
+ # New Python wrapper - use instance method
293
+ return instance.serialize()
294
+ else:
295
+ # Old C++ wrapper type - use direct attribute access
296
+ serialize_dict = {
297
+ "type": "CONDENSED_PHASE_ARRHENIUS",
298
+ "name": instance.name,
299
+ "A": instance.A,
300
+ "B": instance.B,
301
+ "C": instance.C,
302
+ "D": instance.D,
303
+ "E": instance.E,
304
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(instance.reactants),
305
+ "products": ReactionComponentSerializer.serialize_list_reaction_components(instance.products),
306
+ "condensed phase": instance.condensed_phase,
307
+ }
308
+ _add_other_properties(serialize_dict, instance.other_properties)
309
+ return serialize_dict
@@ -0,0 +1,88 @@
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
+ _CondensedPhasePhotolysis = _backend._mechanism_configuration._CondensedPhasePhotolysis
10
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
11
+
12
+
13
+ class CondensedPhasePhotolysis(_CondensedPhasePhotolysis):
14
+ """
15
+ A class representing a condensed phase photolysis reaction rate constant.
16
+
17
+ Attributes:
18
+ name (str): The name of the condensed phase photolysis reaction rate constant.
19
+ scaling_factor (float): The scaling factor for the photolysis rate constant.
20
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
21
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
22
+ condensed_phase (Phase): The condensed phase in which the reaction occurs.
23
+ other_properties (Dict[str, Any]): A dictionary of other properties of the condensed phase photolysis reaction rate constant.
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ name: Optional[str] = None,
29
+ scaling_factor: Optional[float] = None,
30
+ reactants: Optional[List[Union[Species,
31
+ Tuple[float, Species]]]] = None,
32
+ products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
33
+ condensed_phase: Optional[Phase] = None,
34
+ other_properties: Optional[Dict[str, Any]] = None,
35
+ ):
36
+ """
37
+ Initializes the CondensedPhasePhotolysis object with the given parameters.
38
+
39
+ Args:
40
+ name (str): The name of the condensed phase photolysis reaction rate constant.
41
+ scaling_factor (float): The scaling factor for the photolysis rate constant.
42
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
43
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
44
+ condensed_phase (Phase): The condensed phase in which the reaction occurs.
45
+ other_properties (Dict[str, Any]): A dictionary of other properties of the condensed phase photolysis reaction rate constant.
46
+ """
47
+ super().__init__()
48
+ self.name = name if name is not None else self.name
49
+ self.scaling_factor = scaling_factor if scaling_factor is not None else self.scaling_factor
50
+ self.reactants = (
51
+ [
52
+ (
53
+ _ReactionComponent(r.name)
54
+ if isinstance(r, Species)
55
+ else _ReactionComponent(r[1].name, r[0])
56
+ )
57
+ for r in reactants
58
+ ]
59
+ if reactants is not None
60
+ else self.reactants
61
+ )
62
+ self.products = (
63
+ [
64
+ (
65
+ _ReactionComponent(p.name)
66
+ if isinstance(p, Species)
67
+ else _ReactionComponent(p[1].name, p[0])
68
+ )
69
+ for p in products
70
+ ]
71
+ if products is not None
72
+ else self.products
73
+ )
74
+ self.condensed_phase = condensed_phase.name if condensed_phase is not None else self.condensed_phase
75
+ self.other_properties = other_properties if other_properties is not None else self.other_properties
76
+
77
+ @staticmethod
78
+ def serialize(instance) -> Dict:
79
+ serialize_dict = {
80
+ "type": "CONDENSED_PHASE_PHOTOLYSIS",
81
+ "name": instance.name,
82
+ "scaling factor": instance.scaling_factor,
83
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(instance.reactants),
84
+ "products": ReactionComponentSerializer.serialize_list_reaction_components(instance.products),
85
+ "condensed phase": instance.condensed_phase,
86
+ }
87
+ _add_other_properties(serialize_dict, instance.other_properties)
88
+ return serialize_dict