musica 0.12.2__cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.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 (108) hide show
  1. musica/CMakeLists.txt +68 -0
  2. musica/__init__.py +11 -0
  3. musica/_musica.cpython-311-x86_64-linux-gnu.so +0 -0
  4. musica/_musica_gpu.cpython-311-x86_64-linux-gnu.so +0 -0
  5. musica/_version.py +1 -0
  6. musica/backend.py +41 -0
  7. musica/binding_common.cpp +33 -0
  8. musica/binding_common.hpp +7 -0
  9. musica/carma.cpp +911 -0
  10. musica/carma.py +1729 -0
  11. musica/constants.py +3 -0
  12. musica/cpu_binding.cpp +11 -0
  13. musica/cuda.cpp +12 -0
  14. musica/cuda.py +13 -0
  15. musica/examples/__init__.py +1 -0
  16. musica/examples/carma_aluminum.py +124 -0
  17. musica/examples/carma_sulfate.py +246 -0
  18. musica/examples/examples.py +165 -0
  19. musica/examples/sulfate_box_model.py +439 -0
  20. musica/examples/ts1_latin_hypercube.py +245 -0
  21. musica/gpu_binding.cpp +11 -0
  22. musica/main.py +89 -0
  23. musica/mechanism_configuration/__init__.py +1 -0
  24. musica/mechanism_configuration/aqueous_equilibrium.py +274 -0
  25. musica/mechanism_configuration/arrhenius.py +307 -0
  26. musica/mechanism_configuration/branched.py +299 -0
  27. musica/mechanism_configuration/condensed_phase_arrhenius.py +309 -0
  28. musica/mechanism_configuration/condensed_phase_photolysis.py +88 -0
  29. musica/mechanism_configuration/emission.py +71 -0
  30. musica/mechanism_configuration/first_order_loss.py +174 -0
  31. musica/mechanism_configuration/henrys_law.py +44 -0
  32. musica/mechanism_configuration/mechanism_configuration.py +234 -0
  33. musica/mechanism_configuration/phase.py +47 -0
  34. musica/mechanism_configuration/photolysis.py +88 -0
  35. musica/mechanism_configuration/reactions.py +73 -0
  36. musica/mechanism_configuration/simpol_phase_transfer.py +217 -0
  37. musica/mechanism_configuration/species.py +91 -0
  38. musica/mechanism_configuration/surface.py +94 -0
  39. musica/mechanism_configuration/ternary_chemical_activation.py +352 -0
  40. musica/mechanism_configuration/troe.py +352 -0
  41. musica/mechanism_configuration/tunneling.py +250 -0
  42. musica/mechanism_configuration/user_defined.py +88 -0
  43. musica/mechanism_configuration/utils.py +10 -0
  44. musica/mechanism_configuration/wet_deposition.py +52 -0
  45. musica/mechanism_configuration.cpp +607 -0
  46. musica/musica.cpp +201 -0
  47. musica/test/examples/v1/full_configuration/full_configuration.json +466 -0
  48. musica/test/examples/v1/full_configuration/full_configuration.yaml +295 -0
  49. musica/test/integration/test_analytical.py +324 -0
  50. musica/test/integration/test_carma.py +227 -0
  51. musica/test/integration/test_carma_aluminum.py +12 -0
  52. musica/test/integration/test_carma_sulfate.py +17 -0
  53. musica/test/integration/test_chapman.py +139 -0
  54. musica/test/integration/test_sulfate_box_model.py +34 -0
  55. musica/test/integration/test_tuvx.py +62 -0
  56. musica/test/unit/test_parser.py +64 -0
  57. musica/test/unit/test_serializer.py +69 -0
  58. musica/test/unit/test_state.py +325 -0
  59. musica/test/unit/test_util_full_mechanism.py +698 -0
  60. musica/tools/prepare_build_environment_linux.sh +32 -0
  61. musica/tools/prepare_build_environment_macos.sh +1 -0
  62. musica/tools/repair_wheel_gpu.sh +40 -0
  63. musica/tuvx.cpp +93 -0
  64. musica/tuvx.py +199 -0
  65. musica/types.py +407 -0
  66. musica-0.12.2.dist-info/METADATA +473 -0
  67. musica-0.12.2.dist-info/RECORD +111 -0
  68. musica-0.12.2.dist-info/WHEEL +6 -0
  69. musica-0.12.2.dist-info/entry_points.txt +3 -0
  70. musica-0.12.2.dist-info/licenses/AUTHORS.md +59 -0
  71. musica-0.12.2.dist-info/licenses/LICENSE +201 -0
  72. musica.libs/libaec-91f0ca0f.so.0.0.8 +0 -0
  73. musica.libs/libblas-fe34f726.so.3.8.0 +0 -0
  74. musica.libs/libbrotlicommon-6ce2a53c.so.1.0.6 +0 -0
  75. musica.libs/libbrotlidec-811d1be3.so.1.0.6 +0 -0
  76. musica.libs/libcom_err-448cbf49.so.2.1 +0 -0
  77. musica.libs/libcrypt-52aca757.so.1.1.0 +0 -0
  78. musica.libs/libcrypto-bdaed0ea.so.1.1.1k +0 -0
  79. musica.libs/libcurl-c96f124b.so.4.5.0 +0 -0
  80. musica.libs/libdf-2848fafa.so.0.0.0 +0 -0
  81. musica.libs/libgfortran-83c28eba.so.5.0.0 +0 -0
  82. musica.libs/libgssapi_krb5-323bbd21.so.2.2 +0 -0
  83. musica.libs/libhdf5-b5e70f84.so.103.1.0 +0 -0
  84. musica.libs/libhdf5_hl-0b60eabd.so.100.1.2 +0 -0
  85. musica.libs/libidn2-2f4a5893.so.0.3.6 +0 -0
  86. musica.libs/libjpeg-e87d2658.so.62.2.0 +0 -0
  87. musica.libs/libk5crypto-9a74ff38.so.3.1 +0 -0
  88. musica.libs/libkeyutils-2777d33d.so.1.6 +0 -0
  89. musica.libs/libkrb5-a55300e8.so.3.3 +0 -0
  90. musica.libs/libkrb5support-e6594cfc.so.0.1 +0 -0
  91. musica.libs/liblapack-31d7d384.so.3.8.0 +0 -0
  92. musica.libs/liblber-2-d20824ef.4.so.2.10.9 +0 -0
  93. musica.libs/libldap-2-cea2a960.4.so.2.10.9 +0 -0
  94. musica.libs/libmfhdf-38b34047.so.0.0.0 +0 -0
  95. musica.libs/libmvec-2-583a17db.28.so +0 -0
  96. musica.libs/libnetcdf-3915b03a.so.15.0.1 +0 -0
  97. musica.libs/libnetcdff-8cc3a1b0.so.7.0.0 +0 -0
  98. musica.libs/libnghttp2-39367a22.so.14.17.0 +0 -0
  99. musica.libs/libpcre2-8-516f4c9d.so.0.7.1 +0 -0
  100. musica.libs/libpsl-99becdd3.so.5.3.1 +0 -0
  101. musica.libs/libquadmath-2284e583.so.0.0.0 +0 -0
  102. musica.libs/libsasl2-7de4d792.so.3.0.0 +0 -0
  103. musica.libs/libselinux-d0805dcb.so.1 +0 -0
  104. musica.libs/libssh-c11d285b.so.4.8.7 +0 -0
  105. musica.libs/libssl-60250281.so.1.1.1k +0 -0
  106. musica.libs/libsz-0deeef7d.so.2.0.1 +0 -0
  107. musica.libs/libtirpc-cff449a4.so.3.0.0 +0 -0
  108. musica.libs/libunistring-05abdd40.so.2.1.0 +0 -0
@@ -0,0 +1,71 @@
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
+ _Emission = _backend._mechanism_configuration._Emission
10
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
11
+
12
+
13
+ class Emission(_Emission):
14
+ """
15
+ A class representing an emission reaction rate constant.
16
+
17
+ Attributes:
18
+ name (str): The name of the emission reaction rate constant.
19
+ scaling_factor (float): The scaling factor for the emission rate constant.
20
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
21
+ gas_phase (Phase): The gas phase in which the reaction occurs.
22
+ other_properties (Dict[str, Any]): A dictionary of other properties of the emission reaction rate constant.
23
+ """
24
+
25
+ def __init__(
26
+ self,
27
+ name: Optional[str] = None,
28
+ scaling_factor: Optional[float] = None,
29
+ products: Optional[List[Union[Species, Tuple[float, Species]]]] = None,
30
+ gas_phase: Optional[Phase] = None,
31
+ other_properties: Optional[Dict[str, Any]] = None,
32
+ ):
33
+ """
34
+ Initializes the Emission object with the given parameters.
35
+
36
+ Args:
37
+ name (str): The name of the emission reaction rate constant.
38
+ scaling_factor (float): The scaling factor for the emission rate constant.
39
+ products (List[Union[Species, Tuple[float, Species]]]): A list of products formed in the reaction.
40
+ gas_phase (Phase): The gas phase in which the reaction occurs.
41
+ other_properties (Dict[str, Any]): A dictionary of other properties of the emission reaction rate constant.
42
+ """
43
+ super().__init__()
44
+ self.name = name if name is not None else self.name
45
+ self.scaling_factor = scaling_factor if scaling_factor is not None else self.scaling_factor
46
+ self.products = (
47
+ [
48
+ (
49
+ _ReactionComponent(p.name)
50
+ if isinstance(p, Species)
51
+ else _ReactionComponent(p[1].name, p[0])
52
+ )
53
+ for p in products
54
+ ]
55
+ if products is not None
56
+ else self.products
57
+ )
58
+ self.gas_phase = gas_phase.name if gas_phase is not None else self.gas_phase
59
+ self.other_properties = other_properties if other_properties is not None else self.other_properties
60
+
61
+ @staticmethod
62
+ def serialize(instance) -> Dict:
63
+ serialize_dict = {
64
+ "type": "EMISSION",
65
+ "name": instance.name,
66
+ "scaling factor": instance.scaling_factor,
67
+ "products": ReactionComponentSerializer.serialize_list_reaction_components(instance.products),
68
+ "gas phase": instance.gas_phase,
69
+ }
70
+ _add_other_properties(serialize_dict, instance.other_properties)
71
+ return serialize_dict
@@ -0,0 +1,174 @@
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
+ _FirstOrderLoss = _backend._mechanism_configuration._FirstOrderLoss
10
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
11
+ ReactionType = _backend._mechanism_configuration._ReactionType
12
+
13
+
14
+ class FirstOrderLoss:
15
+ """
16
+ A class representing a first-order loss reaction rate constant.
17
+
18
+ Attributes:
19
+ name (str): The name of the first-order loss reaction rate constant.
20
+ scaling_factor (float): The scaling factor for the first-order loss rate constant.
21
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
22
+ gas_phase (Phase): The gas phase in which the reaction occurs.
23
+ other_properties (Dict[str, Any]): A dictionary of other properties of the first-order loss 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
+ gas_phase: Optional[Phase] = None,
33
+ other_properties: Optional[Dict[str, Any]] = None,
34
+ ):
35
+ """
36
+ Initializes the FirstOrderLoss object with the given parameters.
37
+
38
+ Args:
39
+ name (str): The name of the first-order loss reaction rate constant.
40
+ scaling_factor (float): The scaling factor for the first-order loss rate constant.
41
+ reactants (List[Union[Species, Tuple[float, Species]]]): A list of reactants involved in the reaction.
42
+ gas_phase (Phase): The gas phase in which the reaction occurs.
43
+ other_properties (Dict[str, Any]): A dictionary of other properties of the first-order loss reaction rate constant.
44
+ """
45
+ # Create the internal C++ instance
46
+ self._instance = _FirstOrderLoss()
47
+
48
+ # Set properties if provided
49
+ if name is not None:
50
+ self.name = name
51
+ if scaling_factor is not None:
52
+ self.scaling_factor = scaling_factor
53
+ if reactants is not None:
54
+ self.reactants = reactants
55
+ if gas_phase is not None:
56
+ self.gas_phase = gas_phase
57
+ if other_properties is not None:
58
+ self.other_properties = other_properties
59
+
60
+ @property
61
+ def name(self) -> str:
62
+ """Get the name."""
63
+ return self._instance.name
64
+
65
+ @name.setter
66
+ def name(self, value: str):
67
+ """Set the name."""
68
+ self._instance.name = value
69
+
70
+ @property
71
+ def scaling_factor(self) -> float:
72
+ """Get the scaling factor."""
73
+ return self._instance.scaling_factor
74
+
75
+ @scaling_factor.setter
76
+ def scaling_factor(self, value: float):
77
+ """Set the scaling factor."""
78
+ self._instance.scaling_factor = value
79
+
80
+ @property
81
+ def reactants(self) -> List[Union[Species, Tuple[float, Species]]]:
82
+ """Get the reactants as Python objects."""
83
+ # Convert from C++ _ReactionComponent objects to Python Species objects
84
+ result = []
85
+ for rc in self._instance.reactants:
86
+ if hasattr(rc, 'coefficient') and rc.coefficient != 1.0:
87
+ # Create a tuple with coefficient and species
88
+ species = Species(name=rc.species_name)
89
+ result.append((rc.coefficient, species))
90
+ else:
91
+ # Just the species
92
+ species = Species(name=rc.species_name)
93
+ result.append(species)
94
+ return result
95
+
96
+ @reactants.setter
97
+ def reactants(self, value: List[Union[Species, Tuple[float, Species]]]):
98
+ """Set the reactants, converting from Python to C++ objects."""
99
+ cpp_reactants = []
100
+ for r in value:
101
+ if isinstance(r, Species):
102
+ cpp_reactants.append(_ReactionComponent(r.name))
103
+ elif isinstance(r, tuple) and len(r) == 2:
104
+ coefficient, species = r
105
+ cpp_reactants.append(_ReactionComponent(species.name, coefficient))
106
+ else:
107
+ raise ValueError(f"Invalid reactant format: {r}")
108
+ self._instance.reactants = cpp_reactants
109
+
110
+ @property
111
+ def gas_phase(self) -> str:
112
+ """Get the gas phase name."""
113
+ return self._instance.gas_phase
114
+
115
+ @gas_phase.setter
116
+ def gas_phase(self, value: Union[Phase, str]):
117
+ """Set the gas phase."""
118
+ if isinstance(value, Phase):
119
+ self._instance.gas_phase = value.name
120
+ else:
121
+ self._instance.gas_phase = value
122
+
123
+ @property
124
+ def other_properties(self) -> Dict[str, Any]:
125
+ """Get the other properties."""
126
+ return self._instance.other_properties
127
+
128
+ @other_properties.setter
129
+ def other_properties(self, value: Dict[str, Any]):
130
+ """Set the other properties."""
131
+ self._instance.other_properties = value
132
+
133
+ @property
134
+ def type(self):
135
+ """Get the reaction type."""
136
+ return ReactionType.FirstOrderLoss
137
+
138
+ def serialize(self) -> Dict:
139
+ """
140
+ Serialize the FirstOrderLoss object to a dictionary using only Python-visible data.
141
+
142
+ Returns:
143
+ Dict: A dictionary representation of the FirstOrderLoss object.
144
+ """
145
+ serialize_dict = {
146
+ "type": "FIRST_ORDER_LOSS",
147
+ "name": self.name,
148
+ "scaling factor": self.scaling_factor,
149
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(self._instance.reactants),
150
+ "gas phase": self.gas_phase,
151
+ }
152
+ _add_other_properties(serialize_dict, self.other_properties)
153
+ return _remove_empty_keys(serialize_dict)
154
+
155
+ @staticmethod
156
+ def serialize_static(instance) -> Dict:
157
+ """
158
+ Static serialize method for compatibility with C++ _FirstOrderLoss objects.
159
+
160
+ Args:
161
+ instance: The _FirstOrderLoss instance to serialize.
162
+
163
+ Returns:
164
+ Dict: A dictionary representation of the FirstOrderLoss object.
165
+ """
166
+ serialize_dict = {
167
+ "type": "FIRST_ORDER_LOSS",
168
+ "name": instance.name,
169
+ "scaling factor": instance.scaling_factor,
170
+ "reactants": ReactionComponentSerializer.serialize_list_reaction_components(instance.reactants),
171
+ "gas phase": instance.gas_phase,
172
+ }
173
+ _add_other_properties(serialize_dict, instance.other_properties)
174
+ return serialize_dict
@@ -0,0 +1,44 @@
1
+ from typing import Optional, Any, Dict, Union, Tuple
2
+ from .. import backend
3
+ from .phase import Phase
4
+ from .species import Species
5
+ from .utils import _add_other_properties
6
+
7
+ _backend = backend.get_backend()
8
+ _HenrysLaw = _backend._mechanism_configuration._HenrysLaw
9
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
10
+
11
+
12
+ class HenrysLaw(_HenrysLaw):
13
+ """
14
+ A class representing a Henry's law reaction rate constant.
15
+
16
+ Attributes:
17
+ name (str): The name of the Henry's law reaction rate constant.
18
+ other_properties (Dict[str, Any]): A dictionary of other properties of the Henry's law reaction rate constant.
19
+ """
20
+
21
+ def __init__(
22
+ self,
23
+ name: Optional[str] = None,
24
+ other_properties: Optional[Dict[str, Any]] = None,
25
+ ):
26
+ """
27
+ Initializes the HenrysLaw object with the given parameters.
28
+
29
+ Args:
30
+ name (str): The name of the Henry's law reaction rate constant.
31
+ other_properties (Dict[str, Any]): A dictionary of other properties of the Henry's law reaction rate constant.
32
+ """
33
+ super().__init__()
34
+ self.name = name if name is not None else self.name
35
+ self.other_properties = other_properties if other_properties is not None else self.other_properties
36
+
37
+ @staticmethod
38
+ def serialize(instance) -> Dict:
39
+ serialize_dict = {
40
+ "type": "HL_PHASE_TRANSFER",
41
+ "name": instance.name,
42
+ }
43
+ _add_other_properties(serialize_dict, instance.other_properties)
44
+ return serialize_dict
@@ -0,0 +1,234 @@
1
+ # Copyright (C) 2025 University Corporation for Atmospheric Research
2
+ # SPDX-License-Identifier: Apache-2.0
3
+ #
4
+ # This file is part of the musica Python package.
5
+ # For more information, see the LICENSE file in the top-level directory of this distribution.
6
+ from .reactions import Reactions, ReactionType
7
+ from .user_defined import UserDefined, _UserDefined
8
+ from .simpol_phase_transfer import SimpolPhaseTransfer, _SimpolPhaseTransfer
9
+ from .henrys_law import HenrysLaw, _HenrysLaw
10
+ from .wet_deposition import WetDeposition, _WetDeposition
11
+ from .aqueous_equilibrium import AqueousEquilibrium, _AqueousEquilibrium
12
+ from .first_order_loss import FirstOrderLoss, _FirstOrderLoss
13
+ from .emission import Emission, _Emission
14
+ from .condensed_phase_photolysis import CondensedPhasePhotolysis, _CondensedPhasePhotolysis
15
+ from .photolysis import Photolysis, _Photolysis
16
+ from .surface import Surface, _Surface
17
+ from .tunneling import Tunneling, _Tunneling
18
+ from .branched import Branched, _Branched
19
+ from .troe import Troe, _Troe
20
+ from .ternary_chemical_activation import TernaryChemicalActivation, _TernaryChemicalActivation
21
+ from .condensed_phase_arrhenius import CondensedPhaseArrhenius, _CondensedPhaseArrhenius
22
+ from .arrhenius import Arrhenius, _Arrhenius
23
+ from .phase import Phase
24
+ from .species import Species
25
+ import os
26
+ import json
27
+ import yaml
28
+ from typing import Optional, Any, Dict, List
29
+ from .. import backend
30
+
31
+ _backend = backend.get_backend()
32
+ _mc = _backend._mechanism_configuration
33
+ _Mechanism = _mc._Mechanism
34
+ _Version = _mc._Version
35
+ _Parser = _mc._Parser
36
+
37
+
38
+ class Version(_Version):
39
+ """
40
+ A class representing the version of the mechanism.
41
+ """
42
+
43
+
44
+ class Mechanism(_Mechanism):
45
+ """
46
+ A class representing a chemical mechanism.
47
+
48
+ Attributes:
49
+ name (str): The name of the mechanism.
50
+ reactions (List[Reaction]): A list of reactions in the mechanism.
51
+ species (List[Species]): A list of species in the mechanism.
52
+ phases (List[Phase]): A list of phases in the mechanism.
53
+ version (Version): The version of the mechanism.
54
+ """
55
+
56
+ def __init__(
57
+ self,
58
+ name: Optional[str] = None,
59
+ reactions: Optional[List[Any]] = None,
60
+ species: Optional[List[Species]] = None,
61
+ phases: Optional[List[Phase]] = None,
62
+ version: Optional[Version] = None,
63
+ ):
64
+ """
65
+ Initializes the Mechanism object with the given parameters.
66
+
67
+ Args:
68
+ name (str): The name of the mechanism.
69
+ reactions (List[]): A list of reactions in the mechanism.
70
+ species (List[Species]): A list of species in the mechanism.
71
+ phases (List[Phase]): A list of phases in the mechanism.
72
+ version (Version): The version of the mechanism.
73
+ """
74
+ super().__init__()
75
+ self.name = name
76
+ self.species = species if species is not None else []
77
+ self.phases = phases if phases is not None else []
78
+ self.reactions = Reactions(
79
+ reactions=reactions if reactions is not None else [])
80
+ self.version = version if version is not None else Version()
81
+
82
+ def to_dict(self) -> Dict:
83
+ species_list = []
84
+ for species in self.species:
85
+ species_list.append(Species.serialize(species))
86
+
87
+ phases_list = []
88
+ for phase in self.phases:
89
+ phases_list.append(Phase.serialize(phase))
90
+
91
+ reactions_list = []
92
+ for reaction in self.reactions:
93
+ if isinstance(reaction, _Arrhenius):
94
+ # Handle C++ _Arrhenius objects with static serialize call
95
+ reactions_list.append(Arrhenius.serialize_static(reaction))
96
+ elif isinstance(reaction, Arrhenius):
97
+ # Handle Python Arrhenius objects with instance serialize call
98
+ reactions_list.append(reaction.serialize())
99
+ elif isinstance(reaction, _Branched):
100
+ # Handle C++ _Branched objects with static serialize call
101
+ reactions_list.append(Branched.serialize_static(reaction))
102
+ elif isinstance(reaction, Branched):
103
+ # Handle Python Branched objects with instance serialize call
104
+ reactions_list.append(reaction.serialize())
105
+ elif isinstance(reaction, (_CondensedPhaseArrhenius, CondensedPhaseArrhenius)):
106
+ reactions_list.append(
107
+ CondensedPhaseArrhenius.serialize_static(reaction))
108
+ elif isinstance(reaction, (_CondensedPhasePhotolysis, CondensedPhasePhotolysis)):
109
+ reactions_list.append(
110
+ CondensedPhasePhotolysis.serialize(reaction))
111
+ elif isinstance(reaction, (_Emission, Emission)):
112
+ reactions_list.append(Emission.serialize(reaction))
113
+ elif isinstance(reaction, _FirstOrderLoss):
114
+ # Handle C++ _FirstOrderLoss objects with static serialize call
115
+ reactions_list.append(FirstOrderLoss.serialize_static(reaction))
116
+ elif isinstance(reaction, FirstOrderLoss):
117
+ # Handle Python FirstOrderLoss objects with instance serialize call
118
+ reactions_list.append(reaction.serialize())
119
+ elif isinstance(reaction, _SimpolPhaseTransfer):
120
+ # Handle C++ _SimpolPhaseTransfer objects with static serialize call
121
+ reactions_list.append(
122
+ SimpolPhaseTransfer.serialize_static(reaction))
123
+ elif isinstance(reaction, SimpolPhaseTransfer):
124
+ # Handle Python SimpolPhaseTransfer objects with instance serialize call
125
+ reactions_list.append(reaction.serialize())
126
+ elif isinstance(reaction, _AqueousEquilibrium):
127
+ # Handle C++ _AqueousEquilibrium objects with static serialize call
128
+ reactions_list.append(
129
+ AqueousEquilibrium.serialize_static(reaction))
130
+ elif isinstance(reaction, AqueousEquilibrium):
131
+ # Handle Python AqueousEquilibrium objects with instance serialize call
132
+ reactions_list.append(reaction.serialize())
133
+ elif isinstance(reaction, (_WetDeposition, WetDeposition)):
134
+ reactions_list.append(WetDeposition.serialize(reaction))
135
+ elif isinstance(reaction, (_HenrysLaw, HenrysLaw)):
136
+ reactions_list.append(HenrysLaw.serialize(reaction))
137
+ elif isinstance(reaction, (_Photolysis, Photolysis)):
138
+ reactions_list.append(Photolysis.serialize(reaction))
139
+ elif isinstance(reaction, (_Surface, Surface)):
140
+ reactions_list.append(Surface.serialize(reaction))
141
+ elif isinstance(reaction, _Troe):
142
+ # Handle C++ _Troe objects with static serialize call
143
+ reactions_list.append(Troe.serialize_static(reaction))
144
+ elif isinstance(reaction, Troe):
145
+ # Handle Python Troe objects with instance serialize call
146
+ reactions_list.append(reaction.serialize())
147
+ elif isinstance(reaction, _TernaryChemicalActivation):
148
+ # Handle C++ _TernaryChemicalActivation objects with static serialize call
149
+ reactions_list.append(TernaryChemicalActivation.serialize_static(reaction))
150
+ elif isinstance(reaction, TernaryChemicalActivation):
151
+ # Handle Python TernaryChemicalActivation objects with instance serialize call
152
+ reactions_list.append(reaction.serialize())
153
+ elif isinstance(reaction, _Tunneling):
154
+ # Handle C++ _Tunneling objects with static serialize call
155
+ reactions_list.append(Tunneling.serialize_static(reaction))
156
+ elif isinstance(reaction, Tunneling):
157
+ # Handle Python Tunneling objects with instance serialize call
158
+ reactions_list.append(reaction.serialize())
159
+ elif isinstance(reaction, (_UserDefined, UserDefined)):
160
+ reactions_list.append(UserDefined.serialize(reaction))
161
+ else:
162
+ raise TypeError(
163
+ f'Reaction type {type(reaction)} is not supported for export.')
164
+
165
+ return {
166
+ "name": self.name,
167
+ "reactions": reactions_list,
168
+ "species": species_list,
169
+ "phases": phases_list,
170
+ "version": self.version.to_string(),
171
+ }
172
+
173
+ def export(self, file_path: str) -> None:
174
+ MechanismSerializer.serialize(self, file_path)
175
+
176
+
177
+ class Parser(_Parser):
178
+ """
179
+ A class for parsing a chemical mechanism.
180
+ """
181
+
182
+
183
+ class MechanismSerializer():
184
+ """
185
+ A class for exporting a chemical mechanism.
186
+ """
187
+
188
+ @staticmethod
189
+ def _convert_cpp_mechanism_to_python(cpp_mechanism: Any) -> Mechanism:
190
+ """
191
+ Convert a C++ _Mechanism object to a Python Mechanism object.
192
+ """
193
+ reactions_list = []
194
+ for reaction in cpp_mechanism.reactions:
195
+ reactions_list.append(reaction)
196
+
197
+ python_mechanism = Mechanism(
198
+ name=cpp_mechanism.name,
199
+ reactions=reactions_list,
200
+ species=list(cpp_mechanism.species),
201
+ phases=list(cpp_mechanism.phases),
202
+ version=Version() if cpp_mechanism.version is None else cpp_mechanism.version
203
+ )
204
+
205
+ return python_mechanism
206
+
207
+ @staticmethod
208
+ def serialize(mechanism: Mechanism, file_path: str = "./mechanism.json") -> None:
209
+ if not isinstance(mechanism, (Mechanism, _Mechanism)):
210
+ raise TypeError(f"Object {mechanism} is not of type Mechanism.")
211
+
212
+ directory, file = os.path.split(file_path)
213
+ if directory:
214
+ os.makedirs(directory, exist_ok=True)
215
+
216
+ if isinstance(mechanism, _Mechanism) and not isinstance(mechanism, Mechanism):
217
+ mechanism = MechanismSerializer._convert_cpp_mechanism_to_python(
218
+ mechanism)
219
+
220
+ # Now we can use the standard to_dict method
221
+ dictionary = mechanism.to_dict()
222
+
223
+ _, file_ext = os.path.splitext(file)
224
+ file_ext = file_ext.lower()
225
+ if file_ext in ['.yaml', '.yml']:
226
+ with open(file_path, 'w') as file:
227
+ yaml.dump(dictionary, file)
228
+ elif '.json' == file_ext:
229
+ json_str = json.dumps(dictionary, indent=4)
230
+ with open(file_path, 'w') as file:
231
+ file.write(json_str)
232
+ else:
233
+ raise ValueError(
234
+ 'Allowable write formats are .json, .yaml, and .yml')
@@ -0,0 +1,47 @@
1
+ from typing import Optional, Any, Dict, List
2
+ from .. import backend
3
+ from .species import Species
4
+ from .utils import _add_other_properties, _remove_empty_keys
5
+
6
+ _backend = backend.get_backend()
7
+ _Phase = _backend._mechanism_configuration._Phase
8
+
9
+
10
+ class Phase(_Phase):
11
+ """
12
+ A class representing a phase in a chemical mechanism.
13
+
14
+ Attributes:
15
+ name (str): The name of the phase.
16
+ species (List[Species]): A list of species in the phase.
17
+ other_properties (Dict[str, Any]): A dictionary of other properties of the phase.
18
+ """
19
+
20
+ def __init__(
21
+ self,
22
+ name: Optional[str] = None,
23
+ species: Optional[List[Species]] = None,
24
+ other_properties: Optional[Dict[str, Any]] = None,
25
+ ):
26
+ """
27
+ Initializes the Phase object with the given parameters.
28
+
29
+ Args:
30
+ name (str): The name of the phase.
31
+ species (List[Species]): A list of species in the phase.
32
+ other_properties (Dict[str, Any]): A dictionary of other properties of the phase.
33
+ """
34
+ super().__init__()
35
+ self.name = name if name is not None else self.name
36
+ self.species = [
37
+ s.name for s in species] if species is not None else self.species
38
+ self.other_properties = other_properties if other_properties is not None else self.other_properties
39
+
40
+ @staticmethod
41
+ def serialize(instance):
42
+ serialize_dict = {
43
+ "name": instance.name,
44
+ "species": instance.species,
45
+ }
46
+ _add_other_properties(serialize_dict, instance.other_properties)
47
+ return _remove_empty_keys(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
+ _Photolysis = _backend._mechanism_configuration._Photolysis
10
+ _ReactionComponent = _backend._mechanism_configuration._ReactionComponent
11
+
12
+
13
+ class Photolysis(_Photolysis):
14
+ """
15
+ A class representing a photolysis reaction rate constant.
16
+
17
+ Attributes:
18
+ name (str): The name of the 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
+ gas_phase (Phase): The gas phase in which the reaction occurs.
23
+ other_properties (Dict[str, Any]): A dictionary of other properties of the 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
+ gas_phase: Optional[Phase] = None,
34
+ other_properties: Optional[Dict[str, Any]] = None,
35
+ ):
36
+ """
37
+ Initializes the Photolysis object with the given parameters.
38
+
39
+ Args:
40
+ name (str): The name of the 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
+ gas_phase (Phase): The gas phase in which the reaction occurs.
45
+ other_properties (Dict[str, Any]): A dictionary of other properties of the 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.gas_phase = gas_phase.name if gas_phase is not None else self.gas_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": "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
+ "gas phase": instance.gas_phase,
86
+ }
87
+ _add_other_properties(serialize_dict, instance.other_properties)
88
+ return serialize_dict