musica 0.11.1.1__cp312-cp312-win_amd64.whl → 0.14.2__cp312-cp312-win_amd64.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 (129) hide show
  1. musica/__init__.py +23 -3
  2. musica/_musica.cp312-win_amd64.pyd +0 -0
  3. musica/_version.py +1 -1
  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 +165 -0
  13. musica/examples/sulfate_box_model.py +439 -0
  14. musica/examples/ts1_latin_hypercube.py +245 -0
  15. musica/main.py +128 -0
  16. musica/mechanism_configuration/__init__.py +18 -0
  17. musica/mechanism_configuration/ancillary.py +6 -0
  18. musica/mechanism_configuration/arrhenius.py +149 -0
  19. musica/mechanism_configuration/branched.py +140 -0
  20. musica/mechanism_configuration/emission.py +82 -0
  21. musica/mechanism_configuration/first_order_loss.py +90 -0
  22. musica/mechanism_configuration/mechanism.py +93 -0
  23. musica/mechanism_configuration/phase.py +58 -0
  24. musica/mechanism_configuration/phase_species.py +58 -0
  25. musica/mechanism_configuration/photolysis.py +98 -0
  26. musica/mechanism_configuration/reaction_component.py +54 -0
  27. musica/mechanism_configuration/reactions.py +32 -0
  28. musica/mechanism_configuration/species.py +65 -0
  29. musica/mechanism_configuration/surface.py +98 -0
  30. musica/mechanism_configuration/taylor_series.py +136 -0
  31. musica/mechanism_configuration/ternary_chemical_activation.py +160 -0
  32. musica/mechanism_configuration/troe.py +160 -0
  33. musica/mechanism_configuration/tunneling.py +126 -0
  34. musica/mechanism_configuration/user_defined.py +99 -0
  35. musica/mechanism_configuration/utils.py +10 -0
  36. musica/micm/__init__.py +10 -0
  37. musica/micm/conditions.py +49 -0
  38. musica/micm/micm.py +135 -0
  39. musica/micm/solver.py +8 -0
  40. musica/micm/solver_result.py +24 -0
  41. musica/micm/state.py +220 -0
  42. musica/micm/utils.py +18 -0
  43. musica/tuvx/__init__.py +11 -0
  44. musica/tuvx/grid.py +98 -0
  45. musica/tuvx/grid_map.py +167 -0
  46. musica/tuvx/profile.py +130 -0
  47. musica/tuvx/profile_map.py +167 -0
  48. musica/tuvx/radiator.py +95 -0
  49. musica/tuvx/radiator_map.py +173 -0
  50. musica/tuvx/tuvx.py +283 -0
  51. musica-0.14.2.dist-info/DELVEWHEEL +2 -0
  52. {musica-0.11.1.1.dist-info → musica-0.14.2.dist-info}/METADATA +146 -63
  53. musica-0.14.2.dist-info/RECORD +104 -0
  54. {musica-0.11.1.1.dist-info → musica-0.14.2.dist-info}/WHEEL +1 -1
  55. musica-0.14.2.dist-info/entry_points.txt +3 -0
  56. musica-0.14.2.dist-info/licenses/AUTHORS.md +59 -0
  57. musica.libs/libaws-c-auth-0a61a643442f1c0912920b37d9fb0be5.dll +0 -0
  58. musica.libs/libaws-c-cal-eaafa5905de6c9ba274eb8737e6087dd.dll +0 -0
  59. musica.libs/libaws-c-common-b4aa4468297ae8e1664f9380a5510317.dll +0 -0
  60. musica.libs/libaws-c-compression-9f997952aeae03067122ca493c9081b5.dll +0 -0
  61. musica.libs/libaws-c-event-stream-fe9cc8e1692f60c2b5694a8959dbd7c3.dll +0 -0
  62. musica.libs/libaws-c-http-4a9d50ba6ad8882f5267ef89e5e4103a.dll +0 -0
  63. musica.libs/libaws-c-io-e454f1c7a44e77f8c957a016888754be.dll +0 -0
  64. musica.libs/libaws-c-mqtt-67c5fc291740f5cbc5e53fb767e93226.dll +0 -0
  65. musica.libs/libaws-c-s3-206db4af6e1a95637b1921ea596603b9.dll +0 -0
  66. musica.libs/libaws-c-sdkutils-5c9c62dafb8b774cd4a3386f95ef428d.dll +0 -0
  67. musica.libs/libaws-checksums-7e50fe01b862214958f4d2ab4215fde5.dll +0 -0
  68. musica.libs/libaws-cpp-sdk-core-7a9ba9c045ee16f5262e955d96865718.dll +0 -0
  69. musica.libs/libaws-cpp-sdk-s3-4eebff3923c6d250fb508da3c990e0ae.dll +0 -0
  70. musica.libs/libaws-crt-cpp-3173f1e6f504a96d88e8dbf9e04b3b14.dll +0 -0
  71. musica.libs/libbrotlicommon-c62c08223e450dfc2fff33c752cc2285.dll +0 -0
  72. musica.libs/libbrotlidec-ccde7c3978eb1d2e052b193f2968d30a.dll +0 -0
  73. musica.libs/libbz2-1-669a4bf9266d5f020e843aa5fd75b93c.dll +0 -0
  74. musica.libs/libcrypto-3-x64-237eeb55505d067eab5e0b886e519387.dll +0 -0
  75. musica.libs/libcurl-4-bdf865458887dc1235b192ec83729214.dll +0 -0
  76. musica.libs/libgcc_s_seh-1-5a3153f12338f79fbbb7bf095fc5cef1.dll +0 -0
  77. musica.libs/libgfortran-5-90848e0eacdecce3a9005faf5aaec7e7.dll +0 -0
  78. musica.libs/libgomp-1-b8afcf09fecd2f6f01e454c9a5f2c690.dll +0 -0
  79. musica.libs/libhdf5-320-eec6c8ba2fdde30d365786ffbff40989.dll +0 -0
  80. musica.libs/libhdf5_hl-320-7e26e1caaad6be4082d728cf08ab2de4.dll +0 -0
  81. musica.libs/libiconv-2-b37d1b4acab5310c4e4f6e2a961d1464.dll +0 -0
  82. musica.libs/libidn2-0-d17600177f3b4cd2521d595b3472d240.dll +0 -0
  83. musica.libs/libintl-8-e4d4ca6b37338fbb0a8c1246afa7258f.dll +0 -0
  84. musica.libs/liblzma-5-bd95aa0fda6e7c8e41b3843d6fc2942c.dll +0 -0
  85. musica.libs/libnetcdf-0623e518145bddd30cc615b6d7f2f9c1.dll +0 -0
  86. musica.libs/libnetcdff-7-982cb7ee026b78f05a79d00e735f91d1.dll +0 -0
  87. musica.libs/libnghttp2-14-6d49ed806389b4892bcf29c6ed6e3984.dll +0 -0
  88. musica.libs/libnghttp3-9-d3c9b57d760f6dae7d6a067a68126b84.dll +0 -0
  89. musica.libs/libngtcp2-16-a43356e6376d41ce4238e2c55581636a.dll +0 -0
  90. musica.libs/libngtcp2_crypto_ossl-0-b37121badf25a552e5654f27bf6ff093.dll +0 -0
  91. musica.libs/libopenblas-a16595c3cae114c5c7304aa8bb3c1272.dll +0 -0
  92. musica.libs/libpsl-5-4368d4c2412410a4a14f3e7f3227e295.dll +0 -0
  93. musica.libs/libquadmath-0-4edeffe0a60c96360445d33a1876dbda.dll +0 -0
  94. musica.libs/libssh2-1-f407a2b50419bd904c7eb2c101ae81ea.dll +0 -0
  95. musica.libs/libssl-3-x64-d2e43d36e6f87f6f1645717cd0871f86.dll +0 -0
  96. musica.libs/libstdc++-6-83061aaccaf8df77a3b584efef12bc7c.dll +0 -0
  97. musica.libs/libsz-2-d12f3d26417507ec8dea9964f9fe36a1.dll +0 -0
  98. musica.libs/libunistring-5-0473d7a71d94f08292beed694c34f7d1.dll +0 -0
  99. musica.libs/libwinpthread-1-9157bac12a85fb717fa3d2bf6712631a.dll +0 -0
  100. musica.libs/libxml2-16-7fe545d280fdef922282226eef91571f.dll +0 -0
  101. musica.libs/libzip-62d3c877b7842bc509fc000316a4731b.dll +0 -0
  102. musica.libs/libzstd-a25427164f8775046eb8ce488d7d0884.dll +0 -0
  103. musica.libs/zlib1-1dc85208162ee57fe97e892bb5160fe9.dll +0 -0
  104. _musica.cp312-win_amd64.pyd +0 -0
  105. lib/musica.lib +0 -0
  106. lib/yaml-cpp.lib +0 -0
  107. musica/CMakeLists.txt +0 -47
  108. musica/binding.cpp +0 -19
  109. musica/mechanism_configuration.cpp +0 -519
  110. musica/mechanism_configuration.py +0 -1291
  111. musica/musica.cpp +0 -214
  112. musica/test/examples/v0/config.json +0 -7
  113. musica/test/examples/v0/config.yaml +0 -3
  114. musica/test/examples/v0/reactions.json +0 -193
  115. musica/test/examples/v0/reactions.yaml +0 -142
  116. musica/test/examples/v0/species.json +0 -40
  117. musica/test/examples/v0/species.yaml +0 -19
  118. musica/test/examples/v1/full_configuration.json +0 -434
  119. musica/test/examples/v1/full_configuration.yaml +0 -271
  120. musica/test/test_analytical.py +0 -323
  121. musica/test/test_chapman.py +0 -123
  122. musica/test/test_parser.py +0 -693
  123. musica/test/tuvx.py +0 -10
  124. musica/tools/prepare_build_environment_linux.sh +0 -41
  125. musica/tools/prepare_build_environment_windows.sh +0 -22
  126. musica/tools/repair_wheel_gpu.sh +0 -25
  127. musica/types.py +0 -362
  128. musica-0.11.1.1.dist-info/RECORD +0 -30
  129. {musica-0.11.1.1.dist-info → musica-0.14.2.dist-info}/licenses/LICENSE +0 -0
musica/constants.py ADDED
@@ -0,0 +1,3 @@
1
+ AVOGADRO = 6.02214076e23 # mol^-1
2
+ BOLTZMANN = 1.380649e-23 # J K^-1
3
+ GAS_CONSTANT = AVOGADRO * BOLTZMANN # J K^-1 mol^-1
musica/cuda.py ADDED
@@ -0,0 +1,13 @@
1
+ from . import backend
2
+
3
+ _backend = backend.get_backend()
4
+
5
+
6
+ def is_cuda_available() -> bool:
7
+ """
8
+ Check if CUDA is available.
9
+
10
+ Returns:
11
+ bool: True if CUDA is available, False otherwise.
12
+ """
13
+ return _backend._micm._is_cuda_available()
@@ -0,0 +1 @@
1
+ from .examples import Examples
@@ -0,0 +1,124 @@
1
+ """
2
+ Python example for CARMA aluminum aerosols.
3
+
4
+ This script creates one grid box with an initial concentration of aluminum particles
5
+ and allows them to coagulate.
6
+ """
7
+ import xarray as xr
8
+ import numpy as np
9
+ import musica
10
+ import ussa1976
11
+
12
+ available = musica.backend.carma_available()
13
+
14
+
15
+ def run_carma_aluminum_example():
16
+ group = musica.carma.CARMAGroupConfig(
17
+ name="aluminum",
18
+ shortname="PRALUM",
19
+ rmrat=2.0,
20
+ rmin=21.5e-6,
21
+ rmon=21.5e-6,
22
+ ishape=musica.carma.ParticleShape.SPHERE,
23
+ eshape=1.0,
24
+ mie_calculation_algorithm=musica.carma.MieCalculationAlgorithm.TOON_1981,
25
+ is_ice=False,
26
+ is_fractal=True,
27
+ do_wetdep=False,
28
+ do_drydep=True,
29
+ do_vtran=True,
30
+ solfac=0.0,
31
+ scavcoef=0.0,
32
+ df=[1.6] * 5, # 5 bins with fractal dimension 1.6
33
+ falpha=1.0
34
+ )
35
+
36
+ # Create aluminum element
37
+ element = musica.carma.CARMAElementConfig(
38
+ igroup=1,
39
+ isolute=0,
40
+ name="Aluminum",
41
+ shortname="ALUM",
42
+ itype=musica.carma.ParticleType.INVOLATILE,
43
+ icomposition=musica.carma.ParticleComposition.ALUMINUM,
44
+ rho=0.00395, # kg/m3
45
+ arat=[1.0] * 5, # 5 bins with area ratio 1.0
46
+ kappa=0.0,
47
+ )
48
+
49
+ # Create coagulation
50
+ coagulation = musica.carma.CARMACoagulationConfig(
51
+ igroup1=1,
52
+ igroup2=1,
53
+ igroup3=1,
54
+ algorithm=musica.carma.ParticleCollectionAlgorithm.FUCHS)
55
+
56
+ params = musica.carma.CARMAParameters(
57
+ nbin=5,
58
+ nz=1,
59
+ dtime=1800.0,
60
+ groups=[group],
61
+ elements=[element],
62
+ coagulations=[coagulation]
63
+ )
64
+
65
+ FIVE_DAYS_IN_SECONDS = 432000
66
+ params.nstep = FIVE_DAYS_IN_SECONDS // params.dtime
67
+ params.initialization.do_vtran = False
68
+
69
+ n_levels = params.nz
70
+ deltaz = 1000.0
71
+ zmin = 16500.0
72
+
73
+ vertical_center = zmin + (np.arange(n_levels) + 0.5) * deltaz
74
+ vertical_levels = zmin + np.arange(n_levels + 1) * deltaz
75
+
76
+ centered_variables = ussa1976.compute(z=vertical_center, variables=["t", "p", "rho"])
77
+ edge_variables = ussa1976.compute(z=vertical_levels, variables=["p"])
78
+
79
+ temperature = centered_variables.t.values
80
+ pressure = centered_variables.p.values
81
+ pressure_levels = edge_variables.p.values
82
+ density = centered_variables.rho.values
83
+
84
+ carma = musica.carma.CARMA(params)
85
+
86
+ mmr_initial = 5e9 / (deltaz * 2.57474699e14) / density[0]
87
+
88
+ state = carma.create_state(
89
+ time_step=params.dtime,
90
+ temperature=temperature,
91
+ pressure=pressure,
92
+ pressure_levels=pressure_levels,
93
+ vertical_center=vertical_center,
94
+ vertical_levels=vertical_levels,
95
+ longitude=0.0,
96
+ latitude=-105.0,
97
+ coordinates=musica.carma.CarmaCoordinates.CARTESIAN,
98
+ )
99
+
100
+ for i in range(params.nbin):
101
+ for j in range(len(params.elements)):
102
+ state.set_bin(i + 1, j + 1, mmr_initial)
103
+
104
+ bin_data = state.get_bins()
105
+ bin_data = bin_data.expand_dims({"time": [0]})
106
+ env = state.get_environmental_values()
107
+ env = env.expand_dims({"time": [0]})
108
+
109
+ # Run the simulation for the specified number of steps
110
+ for step in range(1, int(params.nstep)):
111
+ state.step()
112
+ bin_data = xr.concat([bin_data, state.get_bins().expand_dims({"time": [step * params.dtime]})], dim="time")
113
+ env = xr.concat([env, state.get_environmental_values().expand_dims(
114
+ {"time": [step * params.dtime]})], dim="time")
115
+
116
+ return xr.merge([bin_data, env])
117
+
118
+
119
+ if __name__ == '__main__':
120
+ if not available:
121
+ print("CARMA backend is not available.")
122
+ else:
123
+ state = run_carma_aluminum_example()
124
+ print(state)
@@ -0,0 +1,246 @@
1
+ """
2
+ Python example for CARMA sulfate that mimics the logic of the CARMA Fortran test.
3
+
4
+ This script creates one grid box with an initial concentration of sulfate particles
5
+ at the smallest size, then allows that to grow using H2SO4 gas. The total mass
6
+ of particles + gas should be conserved.
7
+
8
+ Based on carma_sulfatetest.F90
9
+ """
10
+
11
+ import xarray as xr
12
+ import numpy as np
13
+ import musica
14
+
15
+ available = musica.backend.carma_available()
16
+
17
+
18
+ def run_carma_sulfate_example():
19
+ """Test CARMA sulfate growth from gas condensation in a simple single grid box."""
20
+
21
+ GRAVITY = 9.806 # Acceleration due to gravity in m/s^2
22
+
23
+ # Simplified constants for debugging
24
+ NZ = 1
25
+ NELEM = 1
26
+ NBIN = 38
27
+
28
+ dtime = 1800.0 # Time step in seconds
29
+ deltaz = 10000.0 # Grid box height in meters
30
+ nsteps = int(180000 / dtime)
31
+
32
+ # Sulfate density
33
+ rho_sulfate_kg_m3 = 1923.0 # kg/m³
34
+
35
+ # Grid setup
36
+ latitude = -40.0
37
+ longitude = -105.0
38
+ vertical_center = [17000.0]
39
+ vertical_levels = [vertical_center[0] - deltaz, vertical_center[0] + deltaz]
40
+
41
+ # Standard atmosphere
42
+ pressure_centers = np.array([9000.0])
43
+ temperature_centers = np.array([250.0])
44
+ # this is directly from the original CARMA test, but it seems like there are some unit conversion issues
45
+ air_mass_density_centers = pressure_centers * 10.0 / (8.31430e07 / 28.966 * temperature_centers) * (1.0e-3 * 1.0e6)
46
+ pressure_levels = np.zeros(2)
47
+ pressure_levels[0] = pressure_centers[0] - \
48
+ (vertical_levels[0] - vertical_center[0]) * air_mass_density_centers[0] * GRAVITY
49
+ pressure_levels[1] = pressure_centers[0] - \
50
+ (vertical_levels[1] - vertical_center[0]) * air_mass_density_centers[0] * GRAVITY
51
+
52
+ # Initial mass mixing ratios
53
+ mass_mixing_ratios = {
54
+ "H2O": [1.0e-4],
55
+ "H2SO4": [0.1e-9 * (98.0 / 29.0)],
56
+ "SULFATE": [[0.0 for _ in range(NBIN)]]
57
+ }
58
+ satliq = {
59
+ "H2O": [-1.0],
60
+ "H2SO4": [-1.0]
61
+ }
62
+ satice = {
63
+ "H2O": [-1.0],
64
+ "H2SO4": [-1.0]
65
+ }
66
+
67
+ # Set up CARMA parameters
68
+ params = musica.carma.CARMAParameters()
69
+ params.nz = NZ
70
+ params.nbin = NBIN
71
+
72
+ # Create sulfate group - simplified
73
+ sulfate_group = musica.carma.CARMAGroupConfig(
74
+ name="sulfate",
75
+ shortname="SULF",
76
+ rmin=2.e-10, # Minimum radius in m
77
+ rmrat=2.0, # Mass ratio between bins
78
+ swelling_approach={
79
+ "algorithm": musica.carma.ParticleSwellingAlgorithm.WEIGHT_PERCENT_H2SO4,
80
+ "composition": musica.carma.ParticleSwellingComposition.NONE
81
+ },
82
+ do_drydep=True,
83
+ is_sulfate=True
84
+ )
85
+ params.add_group(sulfate_group)
86
+
87
+ # Create sulfate element
88
+ sulfate_element = musica.carma.CARMAElementConfig(
89
+ igroup=1,
90
+ name="Sulfate",
91
+ shortname="SULF",
92
+ rho=rho_sulfate_kg_m3,
93
+ itype=musica.carma.ParticleType.VOLATILE,
94
+ icomposition=musica.carma.ParticleComposition.SULFURIC_ACID
95
+ )
96
+ params.add_element(sulfate_element)
97
+
98
+ # Create gases - simplified to match successful test_carma.py pattern
99
+ water_gas = musica.carma.CARMAGasConfig(
100
+ name="Water Vapor",
101
+ shortname="H2O",
102
+ wtmol=0.018015, # kg/mol
103
+ ivaprtn=musica.carma.VaporizationAlgorithm.H2O_MURPHY_2005,
104
+ icomposition=musica.carma.GasComposition.H2O,
105
+ dgc_threshold=0.1,
106
+ ds_threshold=0.1
107
+ )
108
+ params.add_gas(water_gas)
109
+
110
+ # Create H2SO4 gas
111
+ h2so4_gas = musica.carma.CARMAGasConfig(
112
+ name="Sulfuric Acid",
113
+ shortname="H2SO4",
114
+ wtmol=0.098079, # kg/mol
115
+ ivaprtn=musica.carma.VaporizationAlgorithm.H2SO4_AYERS_1980,
116
+ icomposition=musica.carma.GasComposition.H2SO4,
117
+ dgc_threshold=0.1,
118
+ ds_threshold=0.1
119
+ )
120
+ params.add_gas(h2so4_gas)
121
+
122
+ # Add growth process
123
+ growth = musica.carma.CARMAGrowthConfig(
124
+ ielem=1, # Sulfate element
125
+ igas=2 # H2SO4 gas
126
+ )
127
+ params.add_growth(growth)
128
+
129
+ # Add nucleation process
130
+ nucleation = musica.carma.CARMANucleationConfig(
131
+ ielemfrom=1,
132
+ ielemto=1,
133
+ algorithm=musica.carma.ParticleNucleationAlgorithm.HOMOGENEOUS_NUCLEATION,
134
+ rlh_nuc=0.0,
135
+ igas=2 # H2SO4 gas
136
+ )
137
+ params.add_nucleation(nucleation)
138
+
139
+ # Add coagulation
140
+ coagulation = musica.carma.CARMACoagulationConfig(
141
+ igroup1=1,
142
+ igroup2=1,
143
+ igroup3=1,
144
+ algorithm=musica.carma.ParticleCollectionAlgorithm.FUCHS
145
+ )
146
+ params.add_coagulation(coagulation)
147
+
148
+ # Initialization
149
+ params.initialization.do_substep = True
150
+ params.initialization.do_thermo = True
151
+ params.initialization.maxretries = 16
152
+ params.initialization.maxsubsteps = 32
153
+ params.initialization.dt_threshold = 1.0
154
+ params.initialization.sulfnucl_method = musica.carma.SulfateNucleationMethod.ZHAO_TURCO.value
155
+
156
+ # Create CARMA instance
157
+ carma = musica.carma.CARMA(params)
158
+
159
+ # Output group properties
160
+ group_props, _ = carma.get_group_properties()
161
+ # Print bin radius and bin mass from group_props xarray Dataset
162
+ for i_bin in range(NBIN):
163
+ print(
164
+ f"Bin {i_bin + 1}: bin radius = {group_props.isel(bin=i_bin)['bin_radius']}; bin mass = {group_props.isel(bin=i_bin)['bin_mass']}"
165
+ )
166
+
167
+ bin_state = None
168
+ gas_state = None
169
+ env_state = None
170
+
171
+ for i_step in range(nsteps):
172
+
173
+ # Create state
174
+ state = carma.create_state(
175
+ time_step=dtime,
176
+ temperature=temperature_centers,
177
+ original_temperature=temperature_centers,
178
+ pressure=pressure_centers,
179
+ pressure_levels=pressure_levels,
180
+ vertical_center=vertical_center,
181
+ vertical_levels=vertical_levels,
182
+ longitude=longitude,
183
+ latitude=latitude,
184
+ coordinates=musica.carma.CarmaCoordinates.CARTESIAN,
185
+ specific_humidity=mass_mixing_ratios["H2O"],
186
+ )
187
+
188
+ # Initialize particle concentrations to zero
189
+ for ibin in range(1, NBIN + 1):
190
+ for ielem in range(1, NELEM + 1):
191
+ state.set_bin(ibin, ielem, mass_mixing_ratios["SULFATE"][0][ibin - 1])
192
+
193
+ # Set H2O concentration
194
+ state.set_gas(
195
+ gas_index=1,
196
+ value=mass_mixing_ratios["H2O"],
197
+ old_mmr=mass_mixing_ratios["H2O"],
198
+ gas_saturation_wrt_ice=satice["H2O"],
199
+ gas_saturation_wrt_liquid=satliq["H2O"],
200
+ )
201
+
202
+ # Set H2SO4 concentration
203
+ state.set_gas(
204
+ gas_index=2,
205
+ value=[mmr * 1.05 for mmr in mass_mixing_ratios["H2SO4"]],
206
+ old_mmr=mass_mixing_ratios["H2SO4"],
207
+ gas_saturation_wrt_ice=satice["H2SO4"],
208
+ gas_saturation_wrt_liquid=satliq["H2SO4"],
209
+ )
210
+
211
+ # Perform model step
212
+ state.step()
213
+ stats = state.get_step_statistics()
214
+ print(f"Step {i_step + 1}/{nsteps}: {stats}")
215
+
216
+ # Get updated state values
217
+ if bin_state is None:
218
+ bin_state = state.get_bins()
219
+ bin_state = bin_state.expand_dims({"time": [i_step * dtime]})
220
+ else:
221
+ bin_state = xr.concat([bin_state, state.get_bins().expand_dims({"time": [i_step * dtime]})], dim="time")
222
+
223
+ if gas_state is None:
224
+ gas_state = state.get_gases()[0]
225
+ gas_state = gas_state.expand_dims({"time": [i_step * dtime]})
226
+ else:
227
+ gas_state = xr.concat([gas_state, state.get_gases()[0].expand_dims({"time": [i_step * dtime]})], dim="time")
228
+
229
+ if env_state is None:
230
+ env_state = state.get_environmental_values()
231
+ env_state = env_state.expand_dims({"time": [i_step * dtime]})
232
+ else:
233
+ env_state = xr.concat([env_state, state.get_environmental_values(
234
+ ).expand_dims({"time": [i_step * dtime]})], dim="time")
235
+
236
+ return env_state, gas_state, bin_state
237
+
238
+
239
+ if __name__ == '__main__':
240
+ if not available:
241
+ print("CARMA backend is not available.")
242
+ else:
243
+ env_state, gas_state, bin_state = run_carma_sulfate_example()
244
+ print(env_state)
245
+ print(gas_state)
246
+ print(bin_state)
@@ -0,0 +1,165 @@
1
+ """MUSICA Examples Module.
2
+
3
+ This module provides a centralized way to access and manage MUSICA examples.
4
+ It defines the Example class for representing individual examples and the
5
+ Examples singleton for accessing all available examples.
6
+
7
+ Example:
8
+ >>> from musica.examples import Examples
9
+ >>> print(Examples.TS1LatinHyperCube)
10
+ >>> for example in Examples:
11
+ ... print(example.name)
12
+ """
13
+
14
+
15
+ class Example:
16
+ """A class representing a MUSICA example.
17
+
18
+ This class encapsulates information about a specific example, including its name,
19
+ short name, description, and file path. It provides methods for string representation
20
+ and class-based construction.
21
+ """
22
+
23
+ def __init__(self, name, short_name, description, path):
24
+ """Initialize an Example instance.
25
+
26
+ Args:
27
+ name (str): The display name of the example.
28
+ short_name (str): A short identifier for the example.
29
+ description (str): A detailed description of what the example demonstrates.
30
+ path (str): The file path to the example script.
31
+ """
32
+ self.name = name
33
+ self.short_name = short_name
34
+ self.description = description
35
+ self.path = path
36
+
37
+ def __str__(self):
38
+ """Return a string representation of the example.
39
+
40
+ Returns:
41
+ str: A formatted string showing the name and description.
42
+ """
43
+ return f'{self.name}: {self.description}'
44
+
45
+ def __repr__(self):
46
+ """Return a string representation of the example for debugging.
47
+
48
+ Returns:
49
+ str: A formatted string showing the name and description.
50
+ """
51
+ return f'{self.name}: {self.description}'
52
+
53
+ @classmethod
54
+ def from_config(cls, display_name, path, short_name, description):
55
+ """Create an Example instance from configuration parameters.
56
+
57
+ This class method provides an alternative constructor that creates an Example
58
+ instance with more explicit parameter naming.
59
+
60
+ Args:
61
+ display_name (str): The display name of the example.
62
+ path (str): The file path to the example script.
63
+ short_name (str): A short identifier for the example.
64
+ description (str): A detailed description of what the example demonstrates.
65
+
66
+ Returns:
67
+ Example: A new Example instance with the provided configuration.
68
+ """
69
+ return cls(name=display_name, short_name=short_name, description=description, path=path)
70
+
71
+
72
+ class _Examples:
73
+ """A container class for managing MUSICA examples.
74
+
75
+ This class provides a centralized way to access and manage all available MUSICA
76
+ examples. It includes predefined examples and supports iteration, indexing, and
77
+ attribute access patterns.
78
+ """
79
+ CARMA_Aluminum = Example.from_config(
80
+ display_name='CARMA Aluminum',
81
+ short_name='CARMA_Aluminum',
82
+ path='carma_aluminum.py',
83
+ description='A CARMA example for simulating aluminum aerosol particles.')
84
+ CARMA_Sulfate = Example.from_config(
85
+ display_name='CARMA Sulfate',
86
+ short_name='CARMA_Sulfate',
87
+ path='carma_sulfate.py',
88
+ description='A CARMA example for simulating sulfate aerosol particles.')
89
+ Sulfate_Box_Model = Example.from_config(
90
+ display_name='Sulfate Box Model',
91
+ short_name='Sulfate_Box_Model',
92
+ path='sulfate_box_model.py',
93
+ description='A box model example for simulating sulfate aerosol particles.')
94
+ TS1LatinHyperCube = Example.from_config(
95
+ display_name='TS1 Latin Hypercube',
96
+ short_name='TS1LatinHyperCube',
97
+ path='ts1_latin_hypercube.py',
98
+ description='A Latin hypercube sampling example for the TS1 mechanism. This script shows how to sample an input space and run multiple box models in parallel on a single mechanism.')
99
+
100
+ @classmethod
101
+ def get_all(cls):
102
+ """Get all available examples.
103
+
104
+ Returns:
105
+ list[Example]: A list of all available Example instances.
106
+ """
107
+ return [cls.CARMA_Aluminum, cls.CARMA_Sulfate, cls.Sulfate_Box_Model, cls.TS1LatinHyperCube]
108
+
109
+ def __iter__(self):
110
+ """Make the class iterable over examples.
111
+
112
+ Returns:
113
+ iterator: An iterator over all available examples.
114
+ """
115
+ return iter(self.get_all())
116
+
117
+ def __getattr__(self, item):
118
+ """Handle attribute access for examples.
119
+
120
+ Args:
121
+ item (str): The attribute name to access.
122
+
123
+ Returns:
124
+ Any: The requested attribute value.
125
+
126
+ Raises:
127
+ AttributeError: If the attribute doesn't exist.
128
+ """
129
+ # Check if the attribute exists in the class definition
130
+ if hasattr(self.__class__, item):
131
+ return getattr(self.__class__, item)
132
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{item}'")
133
+
134
+ def __getitem__(self, item):
135
+ """Support indexing to access examples by position.
136
+
137
+ Args:
138
+ item (int): The index of the example to retrieve.
139
+
140
+ Returns:
141
+ Example: The example at the specified index.
142
+
143
+ Raises:
144
+ IndexError: If the index is out of range.
145
+ """
146
+ return self.get_all()[item]
147
+
148
+ def __repr__(self):
149
+ """Return a string representation for debugging.
150
+
151
+ Returns:
152
+ str: A formatted string showing all available examples.
153
+ """
154
+ return f'Examples: {self.get_all()}'
155
+
156
+ def __str__(self):
157
+ """Return a string representation of the examples collection.
158
+
159
+ Returns:
160
+ str: A formatted string showing all available examples.
161
+ """
162
+ return f'Examples: {self.get_all()}'
163
+
164
+
165
+ Examples = _Examples()