Enabling Your GPU for a Solver in MusicBox#

This tutorial will show you to use utilize a GPU for your MusicBox work. However, this tutorial will not cover how to efficiently use a GPU through parallelization; it will simply introduce getting a GPU set up to run your code. Note: This tutorial requires you to have a Linux GPU-ready environment handy, such as a supercomputing node; it will fail otherwise.

1. Creating a GPU Virtual Environment#

Running code on a GPU requires a different install protocol when setting up a virtual environment. To do so, run these commands in your terminal:

conda create --name music_box_gpu python=3.9
conda activate music_box_gpu
pip install --upgrade setuptools pip wheel
pip install nvidia-pyindex
pip install acom_music_box
pip install musica[gpu]
conda install ipykernel scikit-learn seaborn scipy dask

2. Importing MusicBox#

Importing MusicBox is largerly the same, but with an additional is_cuda_available() function to verify that the GPU is running properly:

[1]:
from acom_music_box import MusicBox, Conditions
import musica.mechanism_configuration as mc
import matplotlib.pyplot as plt
from musica.cuda import is_cuda_available
from musica import SolverType

As with creating the music_box environment in the Basic Workflow Tutorial, this cell may be slow to run the first time.

3. Running a Basic Solver on GPU#

This code is a copy of the Basic Workflow Tutorial, but with an if statement added outside the main code to verify that it is running on a GPU. If you are seeing “Error: No GPU Available” being printed, that means a GPU was not detected; verify that your environment has a GPU.

[2]:
if is_cuda_available():
    # Create each of the species that will be simulated
    X = mc.Species(name="X")
    Y = mc.Species(name="Y")
    Z = mc.Species(name="Z")
    species = {"X": X, "Y": Y, "Z": Z}
    gas = mc.Phase(name="gas", species=list(species.values()))
    # Create the reactions that the species undergo in the
    arr1 = mc.Arrhenius(name="X->Y", A=4.0e-3, C=50, reactants=[species["X"]], products=[species["Y"]], gas_phase=gas)
    arr2 = mc.Arrhenius(name="Y->Z", A=4.0e-3, C=50, reactants=[species["Y"]], products=[species["Z"]], gas_phase=gas)
    rxns = {"X->Y": arr1, "Y->Z": arr2}
    # Create the mechanism that is defined by the species, phases, and reactions
    mechanism = mc.Mechanism(name="tutorial_mechanism", species=list(species.values()), phases=[gas], reactions=list(rxns.values()))
    # Create the box model that contains the mechanism
    box_model = MusicBox()
    box_model.load_mechanism(mechanism, solver_type=SolverType.cuda_rosenbrock)
    # Set the conditions of the box model at time = 0 s
    box_model.initial_conditions = Conditions(
        temperature=298.15, # Units: Kelvin (K)
        pressure=101325.0, # Units: Pascals (Pa)
        species_concentrations={ # Units: mol/m^3
            "X": 3.75,
            "Y": 5.0,
            "Z": 2.5,
        }
    )
    # Set the box model conditions at the defined time
    box_model.add_evolving_condition(
        100.0, # Units: Seconds (s)
        Conditions(
            temperature=75.0, # Units: Kelvin (K)
            pressure=100100.0 # Units: Pascals (Pa)
        )
    )
    # Set the additional configuration options for the box model
    box_model.box_model_options.simulation_length = 200 # Units: Seconds (s)
    box_model.box_model_options.chem_step_time = 1 # Units: Seconds (s)
    box_model.box_model_options.output_step_time = 20 # Units: Seconds (s)
    df = box_model.solve()
    display(df)
    df.plot(x='time.s', y=['CONC.X.mol m-3', 'CONC.Y.mol m-3', 'CONC.Z.mol m-3'], title='Concentration over time', ylabel='Concentration (mol m-3)', xlabel='Time (s)')
    plt.show()
else:
    print("Error: No GPU Available")
Error: No GPU Available