musica 0.14.4__cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.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.
Files changed (92) hide show
  1. musica/__init__.py +11 -0
  2. musica/_musica.cpython-310-aarch64-linux-gnu.so +0 -0
  3. musica/_version.py +1 -0
  4. musica/backend.py +58 -0
  5. musica/carma/__init__.py +20 -0
  6. musica/carma/carma.py +1727 -0
  7. musica/constants.py +3 -0
  8. musica/cuda.py +13 -0
  9. musica/examples/__init__.py +1 -0
  10. musica/examples/carma_aluminum.py +124 -0
  11. musica/examples/carma_sulfate.py +246 -0
  12. musica/examples/examples.py +175 -0
  13. musica/examples/lorenz.py +295 -0
  14. musica/examples/sulfate_box_model.py +439 -0
  15. musica/examples/ts1_latin_hypercube.py +245 -0
  16. musica/main.py +128 -0
  17. musica/mechanism_configuration/__init__.py +18 -0
  18. musica/mechanism_configuration/ancillary.py +6 -0
  19. musica/mechanism_configuration/arrhenius.py +149 -0
  20. musica/mechanism_configuration/branched.py +140 -0
  21. musica/mechanism_configuration/emission.py +82 -0
  22. musica/mechanism_configuration/first_order_loss.py +90 -0
  23. musica/mechanism_configuration/mechanism.py +93 -0
  24. musica/mechanism_configuration/phase.py +58 -0
  25. musica/mechanism_configuration/phase_species.py +58 -0
  26. musica/mechanism_configuration/photolysis.py +98 -0
  27. musica/mechanism_configuration/reaction_component.py +54 -0
  28. musica/mechanism_configuration/reactions.py +32 -0
  29. musica/mechanism_configuration/species.py +65 -0
  30. musica/mechanism_configuration/surface.py +98 -0
  31. musica/mechanism_configuration/taylor_series.py +136 -0
  32. musica/mechanism_configuration/ternary_chemical_activation.py +160 -0
  33. musica/mechanism_configuration/troe.py +160 -0
  34. musica/mechanism_configuration/tunneling.py +126 -0
  35. musica/mechanism_configuration/user_defined.py +99 -0
  36. musica/mechanism_configuration/utils.py +10 -0
  37. musica/micm/__init__.py +10 -0
  38. musica/micm/conditions.py +49 -0
  39. musica/micm/micm.py +135 -0
  40. musica/micm/solver.py +8 -0
  41. musica/micm/solver_result.py +24 -0
  42. musica/micm/state.py +220 -0
  43. musica/micm/utils.py +18 -0
  44. musica/tuvx/__init__.py +11 -0
  45. musica/tuvx/grid.py +98 -0
  46. musica/tuvx/grid_map.py +167 -0
  47. musica/tuvx/profile.py +130 -0
  48. musica/tuvx/profile_map.py +167 -0
  49. musica/tuvx/radiator.py +95 -0
  50. musica/tuvx/radiator_map.py +173 -0
  51. musica/tuvx/tuvx.py +283 -0
  52. musica-0.14.4.dist-info/METADATA +427 -0
  53. musica-0.14.4.dist-info/RECORD +92 -0
  54. musica-0.14.4.dist-info/WHEEL +6 -0
  55. musica-0.14.4.dist-info/entry_points.txt +3 -0
  56. musica-0.14.4.dist-info/licenses/AUTHORS.md +59 -0
  57. musica-0.14.4.dist-info/licenses/LICENSE +201 -0
  58. musica.libs/libaec-34bb4966.so.0.0.8 +0 -0
  59. musica.libs/libblas-8ed0a6f9.so.3.8.0 +0 -0
  60. musica.libs/libbrotlicommon-b6e6c8bd.so.1.0.6 +0 -0
  61. musica.libs/libbrotlidec-5094ef0a.so.1.0.6 +0 -0
  62. musica.libs/libcom_err-6d8d18aa.so.2.1 +0 -0
  63. musica.libs/libcrypt-258f54d5.so.1.1.0 +0 -0
  64. musica.libs/libcrypto-3eda328c.so.1.1.1k +0 -0
  65. musica.libs/libcurl-7faeef02.so.4.5.0 +0 -0
  66. musica.libs/libdf-9661c601.so.0.0.0 +0 -0
  67. musica.libs/libgfortran-e1b7dfc8.so.5.0.0 +0 -0
  68. musica.libs/libgssapi_krb5-fe951f80.so.2.2 +0 -0
  69. musica.libs/libhdf5-463e48d5.so.103.1.0 +0 -0
  70. musica.libs/libhdf5_hl-74316838.so.100.1.2 +0 -0
  71. musica.libs/libidn2-1b2a13b7.so.0.3.6 +0 -0
  72. musica.libs/libjpeg-ee25248c.so.62.2.0 +0 -0
  73. musica.libs/libk5crypto-84470bb3.so.3.1 +0 -0
  74. musica.libs/libkeyutils-fe6e95a9.so.1.6 +0 -0
  75. musica.libs/libkrb5-26ef5d84.so.3.3 +0 -0
  76. musica.libs/libkrb5support-875e89dc.so.0.1 +0 -0
  77. musica.libs/liblapack-8d137073.so.3.8.0 +0 -0
  78. musica.libs/liblber-2-86b08e65.4.so.2.10.9 +0 -0
  79. musica.libs/libldap-2-5c1dd279.4.so.2.10.9 +0 -0
  80. musica.libs/libmfhdf-9c336c5f.so.0.0.0 +0 -0
  81. musica.libs/libnetcdf-71a067be.so.15.0.1 +0 -0
  82. musica.libs/libnetcdff-6a455dd4.so.7.0.0 +0 -0
  83. musica.libs/libnghttp2-3a94c239.so.14.17.0 +0 -0
  84. musica.libs/libpcre2-8-8701a61e.so.0.7.1 +0 -0
  85. musica.libs/libpsl-130094ea.so.5.3.1 +0 -0
  86. musica.libs/libsasl2-076b3c1f.so.3.0.0 +0 -0
  87. musica.libs/libselinux-5700a1fd.so.1 +0 -0
  88. musica.libs/libssh-e0d3bd94.so.4.8.7 +0 -0
  89. musica.libs/libssl-f60bf0e2.so.1.1.1k +0 -0
  90. musica.libs/libsz-81b556a2.so.2.0.1 +0 -0
  91. musica.libs/libtirpc-1fa9018c.so.3.0.0 +0 -0
  92. musica.libs/libunistring-be03fd41.so.2.1.0 +0 -0
@@ -0,0 +1,295 @@
1
+ from musica.micm import MICM, SolverType
2
+ import musica.mechanism_configuration as mc
3
+ import matplotlib.pyplot as plt
4
+ from matplotlib import animation
5
+ from matplotlib.animation import FFMpegWriter, PillowWriter
6
+ import argparse
7
+ import os
8
+ import numpy as np
9
+
10
+
11
+ def full_step(micm, state, time_step):
12
+ """
13
+ Advance the MICM state by a full time step, retrying if necessary.
14
+
15
+ Parameters
16
+ ----------
17
+ micm : MICM
18
+ The MICM solver instance.
19
+ state : MICM.State
20
+ The current state of the system.
21
+ time_step : float
22
+ The time step to advance.
23
+ """
24
+
25
+ elapsed_time = 0
26
+ while elapsed_time < time_step:
27
+ result = micm.solve(state, time_step=time_step)
28
+ elapsed_time += result.stats.final_time
29
+
30
+
31
+ def create_lorenz_mechanism():
32
+ """
33
+ Create a Lorenz mechanism
34
+
35
+ from https://doi.org/10.1007/s11071-025-11622-1
36
+ """
37
+ # Species
38
+ X = mc.Species(name="X")
39
+ Y = mc.Species(name="Y")
40
+ Z = mc.Species(name="Z")
41
+
42
+ # Gas phase
43
+ gas = mc.Phase(name="gas", species=[X, Y, Z])
44
+
45
+ # User-defined reactions
46
+ reactions = [
47
+ mc.UserDefined(
48
+ name="X_decay",
49
+ gas_phase=gas,
50
+ reactants=[X],
51
+ products=[]
52
+ ),
53
+ mc.UserDefined(
54
+ name="Y_to_XY",
55
+ gas_phase=gas,
56
+ reactants=[Y],
57
+ products=[X, Y]
58
+ ),
59
+ mc.UserDefined(
60
+ name="Y_source",
61
+ gas_phase=gas,
62
+ reactants=[],
63
+ products=[Y]
64
+ ),
65
+ mc.UserDefined(
66
+ name="Y_sink",
67
+ gas_phase=gas,
68
+ reactants=[Y],
69
+ products=[]
70
+ ),
71
+ mc.UserDefined(
72
+ name="XY_to_X2Y",
73
+ gas_phase=gas,
74
+ reactants=[X, Y],
75
+ products=[X, Y, Y]
76
+ ),
77
+ mc.UserDefined(
78
+ name="YZ_to_2Y",
79
+ gas_phase=gas,
80
+ reactants=[Y, Z],
81
+ products=[Y, Y]
82
+ ),
83
+ mc.UserDefined(
84
+ name="XYZ_to_X2Z",
85
+ gas_phase=gas,
86
+ reactants=[X, Y, Z],
87
+ products=[X, Z, Z]
88
+ ),
89
+ mc.UserDefined(
90
+ name="Z_source",
91
+ gas_phase=gas,
92
+ reactants=[],
93
+ products=[Z]
94
+ ),
95
+ mc.UserDefined(
96
+ name="Z_autocatalytic",
97
+ gas_phase=gas,
98
+ reactants=[Z],
99
+ products=[Z, Z]
100
+ ),
101
+ mc.UserDefined(
102
+ name="XZ_quench",
103
+ gas_phase=gas,
104
+ reactants=[X, Z],
105
+ products=[X]
106
+ )
107
+ ]
108
+
109
+ # Mechanism
110
+ mechanism = mc.Mechanism(
111
+ name="Lorenz Polynomial CRN",
112
+ species=[X, Y, Z],
113
+ phases=[gas],
114
+ reactions=reactions
115
+ )
116
+ return mechanism
117
+
118
+
119
+ def main(output='lorenz.mp4', fps=30, n=2):
120
+ """
121
+ Run the Lorenz polynomial chemical reaction network simulation and save an animation.
122
+ Parameters
123
+ ----------
124
+ output : str, optional
125
+ Path to the output animation file (e.g., MP4 or GIF) to be written. Defaults
126
+ to ``"lorenz.mp4"``.
127
+ fps : int, optional
128
+ Frames per second for the generated animation. Defaults to 30.
129
+ n : int, optional
130
+ The number of grid cells to simulate the attractor in
131
+ Notes
132
+ -----
133
+ This function constructs the Lorenz mechanism, initializes the MICM solver, sets
134
+ rate parameters and initial concentrations, advances the system for a fixed number
135
+ of time steps, and produces a time-evolving visualization of the state variables.
136
+ """
137
+ mechanism = create_lorenz_mechanism()
138
+
139
+ # Initialize MICM with `n` grid cells (one State containing N cells)
140
+ micm = MICM(mechanism=mechanism, solver_type=SolverType.rosenbrock_standard_order)
141
+ state = micm.create_state(n)
142
+
143
+ # Rate parameters (broadcast to each grid cell)
144
+ mu = 1.0 / 100
145
+ rate_params = {
146
+ "USER.X_decay": 10,
147
+ "USER.Y_to_XY": 10,
148
+ "USER.Y_source": 1 / mu,
149
+ "USER.Y_sink": 1 / mu + 29,
150
+ "USER.XY_to_X2Y": 1 + mu * 28,
151
+ "USER.YZ_to_2Y": 1,
152
+ "USER.XYZ_to_X2Z": mu,
153
+ "USER.Z_source": 8 / (3 * mu),
154
+ "USER.Z_autocatalytic": 1 / mu - 8 / 3,
155
+ "USER.XZ_quench": 1
156
+ }
157
+ # Broadcast scalar rate parameters to lists for each grid cell
158
+ rate_params_broadcast = {k: [v] * n for k, v in rate_params.items()}
159
+ state.set_user_defined_rate_parameters(rate_params_broadcast)
160
+
161
+ # Base initial concentrations for each grid cell; apply small perturbations
162
+ base_init = {"X": 1.0, "Y": 28.0, "Z": 1.0}
163
+ delta = 1e-1
164
+ X_init = [base_init["X"] + i * delta for i in range(n)]
165
+ Y_init = [base_init["Y"] + i * delta for i in range(n)]
166
+ Z_init = [base_init["Z"] for _ in range(n)]
167
+ state.set_concentrations({"X": X_init, "Y": Y_init, "Z": Z_init})
168
+
169
+ nsteps = 2000
170
+ burnout = 200
171
+
172
+ # store trajectories per grid cell: lists of length n containing lists of values
173
+ Xs = [[] for _ in range(n)]
174
+ Ys = [[] for _ in range(n)]
175
+ Zs = [[] for _ in range(n)]
176
+ time_step = 0.01
177
+ for step in range(nsteps):
178
+ # advance the multi-cell state by one time_step
179
+ full_step(micm, state, time_step)
180
+
181
+ if step < burnout:
182
+ continue
183
+
184
+ concs = state.get_concentrations()
185
+ # Ensure arrays and flatten
186
+ Xvals = np.ravel(concs["X"])
187
+ Yvals = np.ravel(concs["Y"])
188
+ Zvals = np.ravel(concs["Z"])
189
+
190
+ # Append each grid cell's current concentration
191
+ for i in range(n):
192
+ Xs[i].append(float(Xvals[i]))
193
+ Ys[i].append(float(Yvals[i]))
194
+ Zs[i].append(float(Zvals[i]))
195
+
196
+ print("Simulation complete.")
197
+
198
+ def create_animation(Xs, Ys, Zs, outpath='lorenz.mp4', fps=30):
199
+ # Xs, Ys, Zs are lists of length n each containing a time-series list
200
+ Ncells = len(Xs)
201
+ if Ncells == 0:
202
+ print("No trajectory data to animate.")
203
+ return
204
+
205
+ fig = plt.figure()
206
+ ax = fig.add_subplot(111, projection='3d')
207
+
208
+ ax.set_xlabel('X Concentration')
209
+ ax.set_ylabel('Y Concentration')
210
+ ax.set_zlabel('Z Concentration')
211
+ ax.set_title('Lorenz Attractor from Chemical Reaction Network')
212
+
213
+ xmin = min(min(xs) for xs in Xs)
214
+ xmax = max(max(xs) for xs in Xs)
215
+ ymin = min(min(ys) for ys in Ys)
216
+ ymax = max(max(ys) for ys in Ys)
217
+ zmin = min(min(zs) for zs in Zs)
218
+ zmax = max(max(zs) for zs in Zs)
219
+ ax.set_xlim(xmin, xmax)
220
+ ax.set_ylim(ymin, ymax)
221
+ ax.set_zlim(zmin, zmax)
222
+ # create one line+point per grid cell
223
+ cmap = plt.get_cmap('tab10')
224
+ colors = [cmap(i % 10) for i in range(Ncells)]
225
+
226
+ lines = []
227
+ points = []
228
+ for idx in range(Ncells):
229
+ ln, = ax.plot([], [], [], lw=1, color=colors[idx], alpha=0.5, label=f'cell {idx}')
230
+ pt, = ax.plot([], [], [], 'o', color=colors[idx], markersize=3)
231
+ lines.append(ln)
232
+ points.append(pt)
233
+
234
+ def init():
235
+ artists = []
236
+ for ln, pt in zip(lines, points):
237
+ ln.set_data([], [])
238
+ ln.set_3d_properties([])
239
+ pt.set_data([], [])
240
+ pt.set_3d_properties([])
241
+ artists.extend([ln, pt])
242
+ return artists
243
+
244
+ def update(i):
245
+ artists = []
246
+ for idx in range(Ncells):
247
+ xs = Xs[idx]
248
+ ys = Ys[idx]
249
+ zs = Zs[idx]
250
+ # clamp i for safety
251
+ j = min(i, len(xs) - 1)
252
+ lines[idx].set_data(xs[:j], ys[:j])
253
+ lines[idx].set_3d_properties(zs[:j])
254
+ if j > 0:
255
+ points[idx].set_data([xs[j - 1]], [ys[j - 1]])
256
+ points[idx].set_3d_properties([zs[j - 1]])
257
+ artists.extend([lines[idx], points[idx]])
258
+ return artists
259
+
260
+ frames = len(Xs[0])
261
+ interval = 1000.0 / fps
262
+
263
+ anim = animation.FuncAnimation(
264
+ fig, update, init_func=init, frames=frames, interval=interval, blit=True)
265
+
266
+ outdir = os.path.dirname(outpath) or '.'
267
+ os.makedirs(outdir, exist_ok=True)
268
+
269
+ try:
270
+ ax.legend()
271
+ writer = FFMpegWriter(fps=fps)
272
+ anim.save(outpath, writer=writer)
273
+ print(f"Saved animation to {outpath}")
274
+ except Exception:
275
+ try:
276
+ gif_path = os.path.splitext(outpath)[0] + '.gif'
277
+ writer = PillowWriter(fps=fps)
278
+ anim.save(gif_path, writer=writer)
279
+ print(f"FFmpeg unavailable; saved GIF to {gif_path}")
280
+ except Exception as e:
281
+ print("Failed to save animation:", e)
282
+
283
+ # Save animation with defaults; CLI can override via args below
284
+ create_animation(Xs, Ys, Zs, outpath=output, fps=fps)
285
+
286
+
287
+ if __name__ == "__main__":
288
+ parser = argparse.ArgumentParser(description='Run Lorenz CRN simulation and create animation')
289
+ parser.add_argument('--output', '-o', default='lorenz.mp4', help='Output movie file (mp4 preferred)')
290
+ parser.add_argument('--fps', type=int, default=30, help='Frames per second for the movie')
291
+ parser.add_argument('--n', type=int, default=2, help='Number of grid cells / trajectories')
292
+ args = parser.parse_args()
293
+
294
+ # Rerun main with requested output and fps
295
+ main(output=args.output, fps=args.fps, n=args.n)