musica 0.11.1.2__cp311-cp311-win_amd64.whl → 0.11.1.4__cp311-cp311-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.

Potentially problematic release.


This version of musica might be problematic. Click here for more details.

musica/CMakeLists.txt CHANGED
@@ -1,47 +1,42 @@
1
- pybind11_add_module(_musica
2
- binding.cpp
3
- musica.cpp
4
- mechanism_configuration.cpp
5
- )
1
+ ################################################################################
2
+ # Python Extension Modules
3
+
4
+ #include(setup_muisca_target)
5
+
6
+ # Define the list of Python extension module targets
7
+ set(PY_MODULES _musica)
6
8
 
7
- target_link_libraries(_musica
8
- PRIVATE
9
- musica::musica
9
+ set(
10
+ MUSICA_PYTHON_SOURCES
11
+ binding_common.cpp
12
+ cuda.cpp
13
+ mechanism_configuration.cpp
14
+ musica.cpp
15
+
16
+ ${MUSICA_SOURCES}
10
17
  )
11
18
 
12
- include(silence_warnings)
13
- silence_warnings(_musica)
14
-
15
- if (APPLE)
16
- # set the rpath for the shared library
17
- set_target_properties(_musica PROPERTIES
18
- INSTALL_RPATH "@loader_path"
19
- BUILD_WITH_INSTALL_RPATH TRUE
20
- )
21
- elseif(UNIX)
22
- set(CUDA_RPATH
23
- "$ORIGIN/../../nvidia/cublas/lib"
24
- "$ORIGIN/../../nvidia/cuda_runtime/lib"
25
- )
26
-
27
- message(STATUS "Adding RPATH for python site packages libs at ${CUDA_RPATH}")
28
-
29
- set_target_properties(_musica PROPERTIES
30
- INSTALL_RPATH "$ORIGIN;${CUDA_RPATH}"
31
- BUILD_WITH_INSTALL_RPATH TRUE
32
- )
19
+ pybind11_add_module(_musica cpu_binding.cpp ${MUSICA_PYTHON_SOURCES})
20
+ musica_setup_target(_musica MODE CPU)
21
+
22
+ if (NOT ${MUSICA_GPU_TYPE} STREQUAL "None")
23
+ pybind11_add_module(_musica_gpu gpu_binding.cpp ${MUSICA_PYTHON_SOURCES})
24
+ musica_setup_target(_musica_gpu MODE GPU)
25
+ list(APPEND PY_MODULES _musica_gpu)
33
26
  endif()
34
27
 
35
- if(WIN32)
36
- # makefiles on windows don't need the config directory
37
- if (${CMAKE_GENERATOR} MATCHES "MinGW Makefiles")
38
- set(PYTHON_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}")
39
- else()
40
- # but visual studio does
41
- set(PYTHON_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>")
28
+ foreach(lib ${PY_MODULES})
29
+ if (APPLE)
30
+ set_target_properties(${lib} PROPERTIES
31
+ INSTALL_RPATH "@loader_path"
32
+ BUILD_WITH_INSTALL_RPATH TRUE
33
+ )
34
+ elseif(UNIX)
35
+ set_target_properties(${lib} PROPERTIES
36
+ INSTALL_RPATH "$ORIGIN"
37
+ BUILD_WITH_INSTALL_RPATH TRUE
38
+ )
42
39
  endif()
43
- else()
44
- set(PYTHON_MODULE_PATH "${CMAKE_CURRENT_BINARY_DIR}")
45
- endif()
46
40
 
47
- install(TARGETS _musica yaml-cpp musica LIBRARY DESTINATION .)
41
+ install(TARGETS ${lib} LIBRARY DESTINATION musica)
42
+ endforeach()
musica/__init__.py CHANGED
@@ -1,3 +1,51 @@
1
- from _musica import *
2
- from .types import *
3
- from .mechanism_configuration import *
1
+ import importlib.util
2
+
3
+
4
+ def _safe_find_spec(name):
5
+ try:
6
+ return importlib.util.find_spec(name)
7
+ except ModuleNotFoundError:
8
+ return None
9
+
10
+
11
+ def _gpu_deps_installed():
12
+ return (
13
+ _safe_find_spec("nvidia.cublas") is not None or
14
+ _safe_find_spec("nvidia_cuda_runtime") is not None or
15
+ _safe_find_spec("nvidia-cublas-cu12") is not None or
16
+ _safe_find_spec("nvidia-cuda-runtime-cu12") is not None
17
+ )
18
+
19
+
20
+ if _gpu_deps_installed():
21
+ from . import _musica_gpu as _backend
22
+ else:
23
+ from . import _musica as _backend
24
+
25
+ # Helper to re-export names from a module
26
+ def _export_all(module, names, globals_):
27
+ for name in names:
28
+ globals_[name] = getattr(module, name)
29
+
30
+
31
+ _core_names = [
32
+ "_Conditions", "_SolverType", "_Solver", "_State", "_create_solver",
33
+ "_create_solver_from_mechanism", "_create_state", "_micm_solve", "_vector_size",
34
+ "_species_ordering", "_user_defined_rate_parameters_ordering",
35
+ ]
36
+ _mechanism_names = [
37
+ "_ReactionType", "_Species", "_Phase", "_ReactionComponent", "_Arrhenius",
38
+ "_CondensedPhaseArrhenius", "_Troe", "_Branched", "_Tunneling", "_Surface",
39
+ "_Photolysis", "_CondensedPhasePhotolysis", "_Emission", "_FirstOrderLoss",
40
+ "_AqueousEquilibrium", "_WetDeposition", "_HenrysLaw", "_SimpolPhaseTransfer",
41
+ "_UserDefined", "_Reactions", "_ReactionsIterator", "_Mechanism", "_Version", "_Parser"
42
+ ]
43
+
44
+ # this allows us to use the same symbols in both the GPU and CPU versionspp
45
+ _export_all(_backend._core, _core_names, globals())
46
+ _export_all(_backend._mechanism_configuration, _mechanism_names, globals())
47
+
48
+ __all__ = _core_names + _mechanism_names
49
+
50
+ from .types import MICM, SolverType, State, Conditions
51
+ from ._version import version as __version__
Binary file
musica/_version.py CHANGED
@@ -1 +1 @@
1
- version = "0.11.1.2"
1
+ version = "0.11.1.4"
@@ -0,0 +1,16 @@
1
+ #include "binding_common.hpp"
2
+
3
+ void bind_cuda(py::module_ &);
4
+ void bind_musica(py::module_ &);
5
+
6
+ void bind_mechanism_configuration(py::module_ &);
7
+
8
+ void bind_all(py::module_ &m) {
9
+ py::module_ core = m.def_submodule("_core", "Wrapper classes for MUSICA C library structs and functions");
10
+ py::module_ mechanism_configuration = m.def_submodule("_mechanism_configuration", "Wrapper classes for Mechanism Configuration library structs and functions");
11
+
12
+ bind_cuda(core);
13
+ bind_musica(core);
14
+
15
+ bind_mechanism_configuration(mechanism_configuration);
16
+ }
@@ -0,0 +1,7 @@
1
+ #pragma once
2
+
3
+ #include <pybind11/pybind11.h>
4
+
5
+ namespace py = pybind11;
6
+
7
+ void bind_all(py::module_ &m);
musica/cpu_binding.cpp ADDED
@@ -0,0 +1,10 @@
1
+ // Copyright (C) 2023-2025 University Corporation for Atmospheric Research
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ #include <pybind11/pybind11.h>
5
+ #include "binding_common.hpp"
6
+
7
+ PYBIND11_MODULE(_musica, m)
8
+ {
9
+ bind_all(m);
10
+ }
musica/cuda.cpp ADDED
@@ -0,0 +1,12 @@
1
+ // Copyright (C) 2023-2025 University Corporation for Atmospheric Research
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ #include <musica/micm/cuda_availability.hpp>
4
+
5
+ #include <pybind11/pybind11.h>
6
+
7
+ namespace py = pybind11;
8
+
9
+ void bind_cuda(py::module_ &cuda)
10
+ {
11
+ cuda.def("_is_cuda_available", &musica::IsCudaAvailable, "Check if CUDA is available");
12
+ }
musica/cuda.py ADDED
@@ -0,0 +1,10 @@
1
+ from . import _backend
2
+
3
+ def is_cuda_available() -> bool:
4
+ """
5
+ Check if CUDA is available.
6
+
7
+ Returns:
8
+ bool: True if CUDA is available, False otherwise.
9
+ """
10
+ return _backend._core._is_cuda_available()
musica/gpu_binding.cpp ADDED
@@ -0,0 +1,10 @@
1
+ // Copyright (C) 2023-2025 University Corporation for Atmospheric Research
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ #include <pybind11/pybind11.h>
5
+ #include "binding_common.hpp"
6
+
7
+ PYBIND11_MODULE(_musica_gpu, m)
8
+ {
9
+ bind_all(m);
10
+ }
@@ -4,7 +4,7 @@
4
4
  # This file is part of the musica Python package.
5
5
  # For more information, see the LICENSE file in the top-level directory of this distribution.
6
6
  from typing import Optional, Any, Dict, List, Union, Tuple
7
- from _musica._mechanism_configuration import (
7
+ from musica import (
8
8
  _ReactionType,
9
9
  _Species,
10
10
  _Phase,
musica/musica.cpp CHANGED
@@ -211,4 +211,4 @@ void bind_musica(py::module_ &core)
211
211
  }, state->state_variant_);
212
212
  },
213
213
  "Print the state to stdout with the current time");
214
- }
214
+ }
@@ -3,7 +3,7 @@ import numpy as np
3
3
  import musica
4
4
  import random
5
5
  import musica.mechanism_configuration as mc
6
- from _musica._core import _is_cuda_available
6
+ from musica.cuda import is_cuda_available
7
7
 
8
8
 
9
9
  def TestSingleGridCell(solver, state, time_step, places=5):
@@ -118,6 +118,7 @@ def TestMultipleGridCell(solver, state, num_grid_cells, time_step, places=5):
118
118
  rate_constants["USER.reaction 2"].append(
119
119
  0.002 + random.uniform(-0.0001, 0.0001))
120
120
 
121
+
121
122
  state.set_conditions(temperatures, pressures) # Air density should be calculated in the state
122
123
  state.set_concentrations(concentrations)
123
124
  state.set_user_defined_rate_parameters(rate_constants)
@@ -127,6 +128,7 @@ def TestMultipleGridCell(solver, state, num_grid_cells, time_step, places=5):
127
128
  initial_temperatures = state.get_conditions()["temperature"]
128
129
  initial_pressures = state.get_conditions()["pressure"]
129
130
  initial_air_density = state.get_conditions()["air_density"]
131
+
130
132
  for i in range(num_grid_cells):
131
133
  assert np.isclose(initial_concentrations["A"][i], concentrations["A"][i], atol=1e-13)
132
134
  assert np.isclose(initial_concentrations["B"][i], concentrations["B"][i], atol=1e-13)
@@ -242,7 +244,7 @@ def GetMechanism():
242
244
 
243
245
  def test_single_grid_cell_standard_rosenbrock():
244
246
  solver = musica.MICM(
245
- config_path="configs/analytical",
247
+ config_path="configs/v0/analytical",
246
248
  solver_type=musica.SolverType.rosenbrock_standard_order)
247
249
  state = solver.create_state()
248
250
  TestSingleGridCell(solver, state, 200.0, 5)
@@ -251,16 +253,16 @@ def test_single_grid_cell_standard_rosenbrock():
251
253
  def test_multiple_grid_cells_standard_rosenbrock():
252
254
  for i in range(1, 11):
253
255
  solver = musica.MICM(
254
- config_path="configs/analytical",
256
+ config_path="configs/v0/analytical",
255
257
  solver_type=musica.SolverType.rosenbrock_standard_order)
256
258
  state = solver.create_state(i)
257
259
  TestMultipleGridCell(solver, state, i, 200.0, 5)
258
260
 
259
261
 
260
262
  def test_cuda_rosenbrock():
261
- if _is_cuda_available():
263
+ if is_cuda_available():
262
264
  solver = musica.MICM(
263
- config_path="configs/analytical",
265
+ config_path="configs/v0/analytical",
264
266
  solver_type=musica.SolverType.cuda_rosenbrock)
265
267
  state = solver.create_state()
266
268
  TestSingleGridCell(solver, state, 200.0, 5)
@@ -270,7 +272,7 @@ def test_cuda_rosenbrock():
270
272
 
271
273
  def test_single_grid_cell_backward_euler():
272
274
  solver = musica.MICM(
273
- config_path="configs/analytical",
275
+ config_path="configs/v0/analytical",
274
276
  solver_type=musica.SolverType.backward_euler_standard_order)
275
277
  state = solver.create_state()
276
278
  TestSingleGridCell(solver, state, 10.0, places=2)
@@ -279,7 +281,7 @@ def test_single_grid_cell_backward_euler():
279
281
  def test_multiple_grid_cells_backward_euler():
280
282
  for i in range(1, 11):
281
283
  solver = musica.MICM(
282
- config_path="configs/analytical",
284
+ config_path="configs/v0/analytical",
283
285
  solver_type=musica.SolverType.backward_euler_standard_order)
284
286
  state = solver.create_state(i)
285
287
  TestMultipleGridCell(solver, state, i, 10.0, places=2)
@@ -287,7 +289,7 @@ def test_multiple_grid_cells_backward_euler():
287
289
 
288
290
  def test_single_grid_cell_rosenbrock():
289
291
  solver = musica.MICM(
290
- config_path="configs/analytical",
292
+ config_path="configs/v0/analytical",
291
293
  solver_type=musica.SolverType.rosenbrock)
292
294
  state = solver.create_state()
293
295
  TestSingleGridCell(solver, state, 200.0, 5)
@@ -296,7 +298,7 @@ def test_single_grid_cell_rosenbrock():
296
298
  def test_multiple_grid_cells_rosenbrock():
297
299
  for i in range(1, 11):
298
300
  solver = musica.MICM(
299
- config_path="configs/analytical",
301
+ config_path="configs/v0/analytical",
300
302
  solver_type=musica.SolverType.rosenbrock)
301
303
  state = solver.create_state(i)
302
304
  TestMultipleGridCell(solver, state, i, 200.0, 5)
@@ -304,7 +306,7 @@ def test_multiple_grid_cells_rosenbrock():
304
306
 
305
307
  def test_single_grid_cell_backward_euler_standard_order():
306
308
  solver = musica.MICM(
307
- config_path="configs/analytical",
309
+ config_path="configs/v0/analytical",
308
310
  solver_type=musica.SolverType.backward_euler_standard_order)
309
311
  state = solver.create_state()
310
312
  TestSingleGridCell(solver, state, 10.0, places=2)
@@ -313,7 +315,7 @@ def test_single_grid_cell_backward_euler_standard_order():
313
315
  def test_multiple_grid_cells_backward_euler_standard_order():
314
316
  for i in range(1, 11):
315
317
  solver = musica.MICM(
316
- config_path="configs/analytical",
318
+ config_path="configs/v0/analytical",
317
319
  solver_type=musica.SolverType.backward_euler_standard_order)
318
320
  state = solver.create_state(i)
319
321
  TestMultipleGridCell(solver, state, i, 10.0, places=2)
@@ -3,9 +3,25 @@ import musica
3
3
  import musica.mechanism_configuration as mc
4
4
 
5
5
 
6
- def test_solve_with_config_path():
6
+ def test_solve_with_config_path_v0():
7
7
  solver = musica.MICM(
8
- config_path="configs/chapman",
8
+ config_path="configs/v0/chapman",
9
+ solver_type=musica.SolverType.rosenbrock_standard_order,
10
+ )
11
+ TestSolve(solver)
12
+
13
+
14
+ def test_solve_with_config_path_v1_json():
15
+ solver = musica.MICM(
16
+ config_path="configs/v1/chapman/config.json",
17
+ solver_type=musica.SolverType.rosenbrock_standard_order,
18
+ )
19
+ TestSolve(solver)
20
+
21
+
22
+ def test_solve_with_config_path_v1_yaml():
23
+ solver = musica.MICM(
24
+ config_path="configs/v1/chapman/config.yaml",
9
25
  solver_type=musica.SolverType.rosenbrock_standard_order,
10
26
  )
11
27
  TestSolve(solver)
@@ -1,6 +1,6 @@
1
1
  import pytest
2
2
  from musica.mechanism_configuration import *
3
- from _musica._mechanism_configuration import _ReactionType
3
+ from musica import _ReactionType
4
4
 
5
5
 
6
6
  def validate_species(species):
@@ -400,7 +400,7 @@ def test_parsed_full_v1_configuration():
400
400
  parser = Parser()
401
401
  extensions = [".yaml", ".json"]
402
402
  for extension in extensions:
403
- path = f"musica/test/examples/v1/full_configuration{extension}"
403
+ path = f"musica/test/examples/v1/full_configuration/full_configuration{extension}"
404
404
  mechanism = parser.parse(path)
405
405
  validate_full_v1_mechanism(mechanism)
406
406
 
@@ -11,7 +11,7 @@ sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo
11
11
  sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-*
12
12
  sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*
13
13
 
14
- yum install -y zip tree
14
+ yum install -y zip tree wget
15
15
 
16
16
  # Use CIBW_ARCHS or CIBW_ARCH if set, else fallback to uname -m
17
17
  if [ -n "$CIBW_ARCHS" ]; then
@@ -32,10 +32,12 @@ if [ "$target_arch" = "x86_64" ]; then
32
32
  sed -i s/^#.*baseurl=http/baseurl=http/g /etc/yum.repos.d/*.repo
33
33
  sed -i s/^mirrorlist=http/#mirrorlist=http/g /etc/yum.repos.d/*.repo
34
34
  yum install --setopt=obsoletes=0 -y \
35
- cuda-nvcc-12-2-12.2.140-1 \
36
- cuda-cudart-devel-12-2-12.2.140-1 \
37
- libcurand-devel-12-2-10.3.3.141-1 \
38
- libcublas-devel-12-2-12.2.5.6-1 \
39
- libnccl-devel-2.19.3-1+cuda12.2
35
+ cuda-nvcc-12-2 \
36
+ cuda-cudart-devel-12-2 \
37
+ libcurand-devel-12-2 \
38
+ libcublas-devel-12-2
40
39
  ln -s cuda-12.2 /usr/local/cuda
40
+
41
+ # list the installed CUDA packages
42
+ tree -L 4 /usr/local/cuda-12.2
41
43
  fi
@@ -7,21 +7,31 @@ for whl in "$2"/*.whl; do
7
7
  tmpdir=$(mktemp -d)
8
8
  unzip -q "$whl" -d "$tmpdir"
9
9
  tree "$tmpdir"
10
- echo "Before patchelf:"
11
- readelf -d "$tmpdir"/_musica*.so
12
- # Use patchelf to fix the rpath and library dependencies
13
- patchelf --remove-rpath "$tmpdir"/_musica*.so
14
- patchelf --set-rpath "\$ORIGIN:\$ORIGIN/../../nvidia/cublas/lib:\$ORIGIN/../../nvidia/cuda_runtime/lib" --force-rpath "$tmpdir"/_musica*.so
15
- # these may need to be periodically updated
16
- patchelf --replace-needed libcudart-b5a066d7.so.12.2.140 libcudart.so.12 "$tmpdir"/_musica*.so
17
- patchelf --replace-needed libcublas-e779a79d.so.12.2.5.6 libcublas.so.12 "$tmpdir"/_musica*.so
18
- patchelf --replace-needed libcublasLt-fbfbc8a1.so.12.2.5.6 libcublasLt.so.12 "$tmpdir"/_musica*.so
19
- # Remove bundled CUDA libraries
20
- rm -f "$tmpdir"/musica.libs/libcudart-*.so*
21
- rm -f "$tmpdir"/musica.libs/libcublas-*.so*
22
- rm -f "$tmpdir"/musica.libs/libcublasLt-*.so*
23
- echo "After patchelf:"
24
- readelf -d "$tmpdir"/_musica*.so
10
+
11
+ so_files=("$tmpdir"/musica/_musica_gpu*.so)
12
+
13
+ if [[ -f "${so_files[0]}" ]]; then
14
+ so_path="${so_files[0]}"
15
+ ls $so_path
16
+ echo "Before patchelf:"
17
+ readelf -d $so_path
18
+ # Use patchelf to fix the rpath and library dependencies
19
+ patchelf --remove-rpath $so_path
20
+ patchelf --set-rpath "\$ORIGIN:\$ORIGIN/../nvidia/cublas/lib:\$ORIGIN/../nvidia/cuda_runtime/lib" --force-rpath $so_path
21
+ # these may need to be periodically updated
22
+ patchelf --replace-needed libcudart-b5a066d7.so.12.2.140 libcudart.so.12 $so_path
23
+ patchelf --replace-needed libcublas-e779a79d.so.12.2.5.6 libcublas.so.12 $so_path
24
+ patchelf --replace-needed libcublasLt-fbfbc8a1.so.12.2.5.6 libcublasLt.so.12 $so_path
25
+ # Remove bundled CUDA libraries
26
+ rm -f "$tmpdir"/musica.libs/libcudart-*.so*
27
+ rm -f "$tmpdir"/musica.libs/libcublas-*.so*
28
+ rm -f "$tmpdir"/musica.libs/libcublasLt-*.so*
29
+ echo "After patchelf:"
30
+ readelf -d $so_path
31
+ else
32
+ echo "No GPU .so file found, skipping patchelf steps"
33
+ fi
34
+
25
35
  # Repack the wheel with correct structure
26
36
  (cd "$tmpdir" && zip -qr "${whl%.whl}.patched.whl" .)
27
37
  rm -rf "$tmpdir"
musica/types.py CHANGED
@@ -3,10 +3,10 @@
3
3
  #
4
4
  # This file is part of the musica Python package.
5
5
  # For more information, see the LICENSE file in the top-level directory of this distribution.
6
- from typing import Optional, Any, Dict, List, Union, Tuple
6
+ from typing import Optional, Dict, List, Union, Tuple
7
7
  from os import PathLike
8
8
  import math
9
- from _musica._core import (
9
+ from musica import (
10
10
  _Conditions,
11
11
  _SolverType,
12
12
  _Solver,
@@ -172,6 +172,7 @@ class State():
172
172
  state.user_defined_rate_parameters[i_param * param_stride + i_cell * cell_stride] = value[k]
173
173
  k += 1
174
174
 
175
+
175
176
  def set_conditions(self,
176
177
  temperatures: Union[Union[float, int], List[Union[float, int]]],
177
178
  pressures: Union[Union[float, int], List[Union[float, int]]],
@@ -358,5 +359,5 @@ class MICM():
358
359
  if not isinstance(time_step, (int, float)):
359
360
  raise TypeError("time_step must be an int or float.")
360
361
  states = state.get_internal_states()
361
- for _, _state in enumerate(states):
362
+ for _state in states:
362
363
  _micm_solve(self.__solver, _state, time_step)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: musica
3
- Version: 0.11.1.2
3
+ Version: 0.11.1.4
4
4
  Summary: MUSICA is a Python library for performing computational simulations in atmospheric chemistry.
5
5
  Author-Email: Matthew Dawsom <mattdawson@ucar.edu>, Jiwon Gim <jiwongim@ucar.edu>, David Fillmore <fillmore@ucar.edu>, Kyle Shores <kshores@ucar.edu>, Montek Thind <mthind@ucar.edu>
6
6
  Maintainer-Email: ACOM MUSICA Developers <musica-support@ucar.edu>
@@ -240,7 +240,110 @@ At present the project encompasses these components
240
240
  - [MICM](https://github.com/NCAR/micm)
241
241
  - Model Independent Chemical Module
242
242
 
243
- ## Available grids
243
+ # Installation
244
+ MUSICA is installable via pip for Python or CMake for C++.
245
+
246
+ ## Pip
247
+ ```
248
+ pip install musica
249
+ ```
250
+ ## CMake
251
+ ```
252
+ $ git clone https://github.com/NCAR/musica.git
253
+ $ cd musica
254
+ $ mkdir build
255
+ $ cd build
256
+ $ ccmake ..
257
+ $ make
258
+ $ make install
259
+ ```
260
+
261
+ # Using the MUSICA Python API
262
+ MUSICA makes its chemical mechanism analysis and visualization available through a Python API. The following example works through solving a simple chemistry system. Please refer to the [official documentation](https://ncar.github.io/musica/index.html) for further tutorials and examples.
263
+ ```
264
+ # --- Import Musica ---
265
+ import musica
266
+ import musica.mechanism_configuration as mc
267
+
268
+ # --- 1. Define the chemical system of interest ---
269
+ A = mc.Species(name="A")
270
+ B = mc.Species(name="B")
271
+ C = mc.Species(name="C")
272
+ species = [A, B, C]
273
+ gas = mc.Phase(name="gas", species=species)
274
+
275
+ # --- 2. Define a mechanism of interest ---
276
+ # Through Musica, several different mechanisms can be explored to define reaction rates. Here, we use the Arrhenius equation as a simple example.
277
+
278
+ r1 = mc.Arrhenius(name="A->B", A=4.0e-3, C=50, reactants=[A], products=[B], gas_phase=gas)
279
+ r2 = mc.Arrhenius(name="B->C", A=1.2e-4, B=2.5, C=75, D=50, E=0.5, reactants=[B], products=[C], gas_phase=gas)
280
+
281
+ mechanism = mc.Mechanism(name="musica_example", species=species, phases=[gas], reactions=[r1, r2])
282
+
283
+ # --- 3. Create MICM solver ---
284
+ # A solver must be initialized with either a configuration file or a mechanism:
285
+
286
+ solver = musica.MICM(mechanism=mechanism, solver_type=musica.SolverType.rosenbrock_standard_order)
287
+
288
+ # --- 4. Define environmental conditions ---
289
+ temperature=300.0
290
+ pressure=101000.0
291
+
292
+ # --- 5. Create and initialize State ---
293
+ # In the model, conditions represent the starting environment for the reactions and are assigned by modifying the state.
294
+
295
+ state = solver.create_state()
296
+ state.set_concentrations({"A": 1.0, "B": 3.0, "C": 5.0})
297
+ state.set_conditions(temperature, pressure)
298
+ initial_pressure = state.get_conditions()['air_density'][0] # store for visualization and output
299
+
300
+ # --- 6. Time parameters ---
301
+ time_step = 4 # stepping
302
+ sim_length = 20 # total simulation time
303
+
304
+ # --- (Optional) 7. Save initial state (t=0) for output visualization ---
305
+ initial_row = {"time.s": 0.0, "ENV.temperature.K": temperature, "ENV.pressure.Pa": pressure, "ENV.air number density.mol m-3": state.get_conditions()['air_density'][0]}
306
+ initial_row.update({f"CONC.{k}.mol m-3": v[0] for k, v in state.get_concentrations().items()})
307
+
308
+ # --- 8. Solve through time loop only ---
309
+ # The following loop simply solves the model per each time step:
310
+
311
+ curr_time = time_step
312
+ while curr_time <= sim_length:
313
+ solver.solve(state, time_step)
314
+ concentrations = state.get_concentrations()
315
+ curr_time += time_step
316
+
317
+ # --- 9. Solve and create DataFrame ---
318
+ # It is likely more useful to solve at each time step and store the associated data:
319
+ import pandas as pd
320
+
321
+ output_data = [] # prepare to store output per time step
322
+ output_data.append(initial_row) # save t=0 data
323
+
324
+ curr_time = time_step
325
+ while curr_time <= sim_length:
326
+ solver.solve(state, time_step)
327
+ row = {
328
+ "time.s": curr_time,
329
+ "ENV.temperature.K": state.get_conditions()['temperature'][0],
330
+ "ENV.pressure.Pa": state.get_conditions()['pressure'][0],
331
+ "ENV.air number density.mol m-3": state.get_conditions()['air_density'][0]
332
+ }
333
+ row.update({f"CONC.{k}.mol m-3": v[0] for k, v in state.get_concentrations().items()})
334
+ output_data.append(row)
335
+ curr_time += time_step
336
+
337
+ df = pd.DataFrame(output_data)
338
+ print(df)
339
+
340
+ # --- 10. Visualize Specific Results ---
341
+ import matplotlib.pyplot as plt
342
+
343
+ df.plot(x='time.s', y=['CONC.A.mol m-3', 'CONC.B.mol m-3', 'CONC.C.mol m-3'], title='Concentration over time', ylabel='Concentration (mol m-3)', xlabel='Time (s)')
344
+ plt.show()
345
+ ```
346
+ # Available grids
244
347
 
245
348
  Pre-made grids for use in MUSICA are available [here](https://wiki.ucar.edu/display/MUSICA/Available+Grids).
246
349
 
@@ -282,7 +385,25 @@ Specifying a specific version of `tuv-x` by has, but using the official reposito
282
385
  ### Python build
283
386
  Musica has python bindings. If you want to install the python package, you may `pip install musica`.
284
387
 
285
- To build the package locally,
388
+ #### PyPi
389
+ If you only want to use the CPU components,
390
+
391
+ ```
392
+ pip install musica
393
+ ```
394
+
395
+ Note that GPU support has only been tested on linux. If you have an NVIDIA GPU and would like to take
396
+ advantage of our GPU solver, you must first [add the NVIDIA pypi index](https://docs.nvidia.com/cuda/cuda-quick-start-guide/#pip-wheels-linux) and then install musica with our gpu option.
397
+
398
+ ```
399
+ pip install --upgrade setuptools pip wheel
400
+ pip install nvidia-pyindex
401
+ pip install musica[gpu]
402
+ ```
403
+
404
+ #### Local build
405
+
406
+ Musica has python bindings. To build the package locally,
286
407
 
287
408
  ```
288
409
  pip install -e .
@@ -0,0 +1,33 @@
1
+ musica/__init__.py,sha256=-TtiqPge1QqHDQHJLZb1S13378oCvioqxveGFsTG1K4,1799
2
+ musica/_musica.cp311-win_amd64.pyd,sha256=Kj07fk879aAzDBEzBjVAwN8IeFmt0w2Zq79rhcashus,1497088
3
+ musica/_version.py,sha256=8qJ5k0-ETwr6dVZPpj6tTjKpDf7mxlh9RCLnW4-0JlI,22
4
+ musica/binding_common.cpp,sha256=A1Y5LxGjWXi09Eczv06H5iJC-9i0R9eya2ehz2jnD9U,575
5
+ musica/binding_common.hpp,sha256=YAcb9WnfXL7Ps-rR-iMBSwUgBQZfZZdCQQod5CTMEZA,108
6
+ musica/CMakeLists.txt,sha256=qRSE9QuzRR1go16-ujVBHpkdHf-5dCuPZLbCrP7ygHc,1092
7
+ musica/cpu_binding.cpp,sha256=J-9SfvuXeWYvOAwX5luG6f5DieV0pchkutRAJ3xoN2Y,234
8
+ musica/cuda.cpp,sha256=oTG2ZnL-SiW2kx9eL4XJOQGJeIiGuy8tJ5BEoLRWL4M,358
9
+ musica/cuda.py,sha256=6Qe6cBbPN9K5Uqu7wBt18zTUjRIgvnQKBJZr6tHJrs8,234
10
+ musica/gpu_binding.cpp,sha256=sv1_exUAhGRXY0kzT_q-f0Yl_GYgkYRKwmqWGSi0Qx8,238
11
+ musica/mechanism_configuration.cpp,sha256=JXGAO3j1EEKYdswjrtX8J3KcI_YlfS9WGRmlMxctaDw,27619
12
+ musica/mechanism_configuration.py,sha256=4aAPN-tN0q6RFMe9s-W94--Llu4Q7V5t_IpO1PVgL-w,59276
13
+ musica/musica.cpp,sha256=w6kI-mrUqNbJPeYuuPzzsDrb7GsHy2bKNoOt0b8tJTY,8614
14
+ musica/test/examples/v0/config.json,sha256=JDQdrDNRmRXGYlytX1uiSDV1lkYIAneLwlodHKFw-os,85
15
+ musica/test/examples/v0/config.yaml,sha256=r31QbiFE2YDudGxLGpTKnpyveTnlfXeLgJ2qSrQddDY,47
16
+ musica/test/examples/v0/reactions.json,sha256=SmRUE5XOAv0h3HOWg4Fb1swBiZvZ-1hsIrmMCJqEVIk,4380
17
+ musica/test/examples/v0/reactions.yaml,sha256=5QeEkhjeAL_rXxNYCLOuqDUudTmgwLW3NERDupKpj6s,2408
18
+ musica/test/examples/v0/species.json,sha256=klFuYb2vAtWdHfHJVYuIuPe_6LHRTuB0Aw29YhwfCFc,604
19
+ musica/test/examples/v0/species.yaml,sha256=ECT9DDa2GMwhSRaRLxjOiCATTKkTRTPwugRsUjHSytY,302
20
+ musica/test/examples/v1/full_configuration/full_configuration.json,sha256=1-kr2bZJvfuENfy6FMfc5ZEOtgs_NhzHYeGrEGLqLMw,9240
21
+ musica/test/examples/v1/full_configuration/full_configuration.yaml,sha256=9NSd8BUJnJ6CPjX9ZngqbFDEqUf1qG5ixbnQDO2m79k,5505
22
+ musica/test/test_analytical.py,sha256=6-H8OKGj83qF9_JD_1XxcoHkljrWbZWNuzX5RAFIHuI,14125
23
+ musica/test/test_chapman.py,sha256=t6p0CadUy-B4OP7A-EZ9Wz52diuYs5yc9LKiFUS9T6A,3651
24
+ musica/test/test_parser.py,sha256=Pf-I4CSJ1aMfRl8meVsuIsLSXd-eOqZW_JM5_zjD-IA,24978
25
+ musica/test/tuvx.py,sha256=L8X7rJ09HiRlrhLK6fjircI8tGHnFCZJzVow8He5YOE,126
26
+ musica/tools/prepare_build_environment_linux.sh,sha256=kdcBj9qELh811OzY8o5tQDAnLXJFXqzwIkZmkRAcLFY,1500
27
+ musica/tools/prepare_build_environment_windows.sh,sha256=sBBWhJQaS2zWDVFLIDMNBMOMPw8auXwnwz7nhuB5Q_k,847
28
+ musica/tools/repair_wheel_gpu.sh,sha256=nQueyGNC2qWcBAicjVdAfB6JH4m_51dFOG83vVxke54,1525
29
+ musica/types.py,sha256=GKQ9L68bGbid6qYEykmFVBOxYCptXztt9xsRvHFmGmo,15233
30
+ musica-0.11.1.4.dist-info/METADATA,sha256=3S0lnuWJjva1wxEFXEmDsnNI1NO0Y1TY1W3RXgAJUoo,25120
31
+ musica-0.11.1.4.dist-info/WHEEL,sha256=snOjF3_Qdfl83AvEPF_jBYJIRsss89-Tk83TV05TAGs,106
32
+ musica-0.11.1.4.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
33
+ musica-0.11.1.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: scikit-build-core 0.11.3
2
+ Generator: scikit-build-core 0.11.4
3
3
  Root-Is-Purelib: false
4
4
  Tag: cp311-cp311-win_amd64
5
5
 
Binary file
lib/musica.lib DELETED
Binary file
lib/yaml-cpp.lib DELETED
Binary file
musica/binding.cpp DELETED
@@ -1,19 +0,0 @@
1
- // Copyright (C) 2023-2025 University Corporation for Atmospheric Research
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- #include <pybind11/pybind11.h>
5
-
6
- namespace py = pybind11;
7
-
8
- void bind_musica(py::module_ &);
9
- void bind_mechanism_configuration(py::module_ &);
10
-
11
- // Wraps micm.cpp
12
- PYBIND11_MODULE(_musica, m)
13
- {
14
- py::module_ core = m.def_submodule("_core", "Wrapper classes for MUSICA C library structs and functions");
15
- py::module_ mechanism_configuration = m.def_submodule("_mechanism_configuration", "Wrapper classes for Mechanism Configuration library structs and functions");
16
-
17
- bind_musica(core);
18
- bind_mechanism_configuration(mechanism_configuration);
19
- }
@@ -1,30 +0,0 @@
1
- _musica.cp311-win_amd64.pyd,sha256=2oWGkjguo1aa4I0jLXk89aaRIGC4bN8IuNNmeU4Rx3U,1516544
2
- lib/musica.lib,sha256=3fOE_fGdJpQcu6jQOtZPSg6DloXqkxqtqqOLmXUKR34,5507286
3
- lib/yaml-cpp.lib,sha256=c6-gZGYvou9dZX2bXseVetNJ3RQvpnMBYXNDlxTB7EQ,2764186
4
- musica/__init__.py,sha256=ZtW55jXUkE_2GFco1Q1GyGrpyNoVej6gfbpEWHzfpM0,85
5
- musica/_version.py,sha256=Q-neckHF6Bee2eqnfo7VN5R_4zuG4-FYCTHp3IILvdM,22
6
- musica/binding.cpp,sha256=rpc7Fn_GmR2Femli_gEvtgtiprRnForekUlMDoBo7PQ,674
7
- musica/CMakeLists.txt,sha256=j5m-7lf8E1YwpiEeUml5GL27hS4sfpgn2h2LzoQDiO8,1174
8
- musica/mechanism_configuration.cpp,sha256=JXGAO3j1EEKYdswjrtX8J3KcI_YlfS9WGRmlMxctaDw,27619
9
- musica/mechanism_configuration.py,sha256=_0kS0fvGS-CbQ_YfJOeSM416u7WLPwq7GzDcPgGGBWA,59302
10
- musica/musica.cpp,sha256=z4nucF98Nd-V6U_OLp_5RsW4WGE8qMn3GWLvCuY_nJE,8612
11
- musica/test/examples/v0/config.json,sha256=JDQdrDNRmRXGYlytX1uiSDV1lkYIAneLwlodHKFw-os,85
12
- musica/test/examples/v0/config.yaml,sha256=r31QbiFE2YDudGxLGpTKnpyveTnlfXeLgJ2qSrQddDY,47
13
- musica/test/examples/v0/reactions.json,sha256=SmRUE5XOAv0h3HOWg4Fb1swBiZvZ-1hsIrmMCJqEVIk,4380
14
- musica/test/examples/v0/reactions.yaml,sha256=5QeEkhjeAL_rXxNYCLOuqDUudTmgwLW3NERDupKpj6s,2408
15
- musica/test/examples/v0/species.json,sha256=klFuYb2vAtWdHfHJVYuIuPe_6LHRTuB0Aw29YhwfCFc,604
16
- musica/test/examples/v0/species.yaml,sha256=ECT9DDa2GMwhSRaRLxjOiCATTKkTRTPwugRsUjHSytY,302
17
- musica/test/examples/v1/full_configuration.json,sha256=1-kr2bZJvfuENfy6FMfc5ZEOtgs_NhzHYeGrEGLqLMw,9240
18
- musica/test/examples/v1/full_configuration.yaml,sha256=9NSd8BUJnJ6CPjX9ZngqbFDEqUf1qG5ixbnQDO2m79k,5505
19
- musica/test/test_analytical.py,sha256=lY5XuEMEg7IEfTvEIeSRhShMNdX39q00H8RjqGnZB30,14098
20
- musica/test/test_chapman.py,sha256=_OHLNBWT5qcU8s3mQAisV16qOdyRq7gdaU4nFZtxTnY,3193
21
- musica/test/test_parser.py,sha256=s8b55MntiDmUeW3GP_-JHucEhxi5RMSzPWQULM73rpg,24985
22
- musica/test/tuvx.py,sha256=L8X7rJ09HiRlrhLK6fjircI8tGHnFCZJzVow8He5YOE,126
23
- musica/tools/prepare_build_environment_linux.sh,sha256=Xrd95nPnznqTAc24TVeehXP-7uMkJE1FysKKZsPYgPs,1507
24
- musica/tools/prepare_build_environment_windows.sh,sha256=sBBWhJQaS2zWDVFLIDMNBMOMPw8auXwnwz7nhuB5Q_k,847
25
- musica/tools/repair_wheel_gpu.sh,sha256=-_Bh2fWv_RE5N02CVEbMh8PMZ0ecygk-DafsCIaALdg,1347
26
- musica/types.py,sha256=GA04nbo-m7Jg_TQMvFMdMC35kzSDynUHvt7alBnM8FI,15257
27
- musica-0.11.1.2.dist-info/METADATA,sha256=Aehj-KwjLoVTpAFwaocvKadc3T-meJRaq_OhiK8qRyM,20814
28
- musica-0.11.1.2.dist-info/WHEEL,sha256=XudZ88buj5mYv1il7ey7lY9YY_b5GZq6c5RjX3rDALo,106
29
- musica-0.11.1.2.dist-info/licenses/LICENSE,sha256=HrhfyXIkWY2tGFK11kg7vPCqhgh5DcxleloqdhrpyMY,11558
30
- musica-0.11.1.2.dist-info/RECORD,,