Heating and Cooling in UCLCHEM#
This notebook demonstheating how to use UCLCHEM with heating and cooling mechanisms enabled. UCLCHEM includes a comprehensive set of heating and cooling processes that can significantly affect the temperature evolution and chemistry in astrophysical environments.
Overview#
UCLCHEM can track gas temperature changes due to:
Heating processes:
Photoelectric heating from PAHs and dust grains
H₂ formation heating
H₂ photodissociation heating
Cosmic ray heating
Chemical reaction enthalpy (optional)
X-ray heating
Turbulent heating
And more…
Cooling processes:
Line cooling (CO, H₂O, OH, etc.)
Continuum cooling from dust
Atomic fine structure cooling (C⁺, O, etc.)
Recombination cooling
And more…
By default, heating is enabled (heatingFlag=True), but you can turn it off or customize which processes are included.
import uclchem
import matplotlib.pyplot as plt
Example 1: Basic Model with Heating Enabled#
Let’s start with a simple cloud model with heating and cooling enabled (the default behavior). We’ll model a molecular cloud core at constant density.
# Define parameters for a molecular cloud with heating enabled
param_dict_heating = {
"initialDens": 1e4, # Initial density (cm^-3)
"initialTemp": 10.0, # Initial temperature (K)
"finalTime": 1.0e6, # Final time (years)
"baseAv": 10.0, # Visual extinction
"rout": 0.1, # Outer radius (pc)
"freefall": False, # Keep constant density
"heatingFlag": True, # Enable heating (default)
}
# Run the model using the Cloud class
cloud = uclchem.model.Cloud(param_dict=param_dict_heating)
# Extract data from the model object
physics, abundances = cloud.get_dataframes(joined=False)
_, _, rates = cloud.get_dataframes(joined=False, with_rates=True)
_, _, heating = cloud.get_dataframes(joined=False, with_heating=True)
start_abund = cloud.next_starting_chemistry_array
flag = 0 if cloud.has_attr("_data") else -1
print(f"Model completed with flag: {flag}")
if flag < 0:
print(f"Error: Model failed to complete")
else:
print("Success! Model completed.")
print(
f"\nTemperature range: {physics['gasTemp'].min():.2f} - {physics['gasTemp'].max():.2f} K"
)
print(
f"Density range: {physics['Density'].min():.2e} - {physics['Density'].max():.2e} cm^-3"
)
Model completed with flag: -1
Error: Model failed to complete
Visualizing Temperature Evolution#
The physics DataFrame contains physical properties including gas temperature. Let’s plot how temperature evolves over time.
# Plot temperature evolution
fig, ax = plt.subplots(figsize=(10, 6))
ax.plot(physics["Time"], physics["gasTemp"], linewidth=2, color="darkred")
ax.set_xlabel("Time (years)", fontsize=12)
ax.set_ylabel("Gas Temperature (K)", fontsize=12)
ax.set_xscale("log")
ax.set_title("Gas Temperature Evolution with Heating/Cooling", fontsize=14)
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Example 2: Comparing Heating On vs Off#
To see the impact of heating/cooling processes, let’s run two models side by side: one with heating enabled and one without.
# Model WITHOUT heating
param_dict_no_heating = param_dict_heating.copy()
param_dict_no_heating["heatingFlag"] = False
cloud_no_heat = uclchem.model.Cloud(param_dict=param_dict_no_heating)
# Extract data
physics_no_heat, abundances_no_heat = cloud_no_heat.get_dataframes(joined=False)
_, _, rates_no_heat = cloud_no_heat.get_dataframes(joined=False, with_rates=True)
_, _, heating_no_heat = cloud_no_heat.get_dataframes(joined=False, with_heating=True)
flag_no_heat = 0 if cloud_no_heat.has_attr("_data") else -1
print(f"No heating model completed with flag: {flag_no_heat}")
# Compare the two runs
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Temperature comparison
axes[0].plot(physics["Time"], physics["gasTemp"], label="Heating ON", linewidth=2)
axes[0].plot(
physics_no_heat["Time"],
physics_no_heat["gasTemp"],
label="Heating OFF",
linewidth=2,
linestyle="--",
)
axes[0].set_xlabel("Time (years)", fontsize=12)
axes[0].set_ylabel("Gas Temperature (K)", fontsize=12)
axes[0].set_xscale("log")
axes[0].set_title("Temperature Evolution", fontsize=14)
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# Compare a key chemical species (CO)
axes[1].plot(physics["Time"], abundances["H2O"], label="Heating ON", linewidth=2)
axes[1].plot(
physics_no_heat["Time"],
abundances_no_heat["H2O"],
label="Heating OFF",
linewidth=2,
linestyle="--",
)
axes[1].set_xlabel("Time (years)", fontsize=12)
axes[1].set_ylabel("H$_2$O Abundance", fontsize=12)
axes[1].set_xscale("log")
axes[1].set_yscale("log")
axes[1].set_title("CO Abundance Evolution", fontsize=14)
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print("\nFinal temperatures:")
print(f" With heating: {physics['gasTemp'].iloc[-1]:.2f} K")
print(f" Without heating: {physics_no_heat['gasTemp'].iloc[-1]:.2f} K")
No heating model completed with flag: -1
Final temperatures:
With heating: 13.10 K
Without heating: 10.00 K
Example 3: Accessing Heating and Cooling Rates#
UCLCHEM can return detailed heating and cooling rates when you use return_dataframe=True with the rates arrays. The heating DataFrame includes individual contributions from each heating and cooling process.
# The heating DataFrame contains heating and cooling information
print("Available heating/cooling columns:")
print(heating.columns.tolist()[:20], "...") # Show first 20 columns
# Extract heating and cooling columns
heating_cols = [
col for col in heating.columns if "heating" in col.lower() and col != "Time"
]
cooling_cols = [col for col in heating.columns if "cooling" in col.lower()]
print(f"\nFound {len(heating_cols)} heating processes")
print(f"Found {len(cooling_cols)} cooling processes")
# Show the heating processes
print("\nHeating processes:")
for col in heating_cols[:10]: # Show first 10
print(f" - {col}")
Available heating/cooling columns:
['Time', 'AtomicLineEmission Cooling', 'H2CollisionallyInduced Cooling', 'Compton Cooling', 'ContinuumEmission Cooling', 'MolecularLine Cooling', 'H Line Cooling', 'C+ Line Cooling', 'O Line Cooling', 'C Line Cooling', 'CO Line Cooling', 'p-H2 Line Cooling', 'o-H2 Line Cooling', 'PhotoelectricBakes Heating', 'PhotoelectricWeingartner Heating', 'H2Formation Heating', 'H2Photodissociation Heating', 'H2FUVPumping Heating', 'CarbonIonization Heating', 'CosmicRay Heating'] ...
Found 10 heating processes
Found 12 cooling processes
Heating processes:
- PhotoelectricBakes Heating
- PhotoelectricWeingartner Heating
- H2Formation Heating
- H2Photodissociation Heating
- H2FUVPumping Heating
- CarbonIonization Heating
- CosmicRay Heating
- Turbulent Heating
- GasGrainCollisions Heating
- Chemical Heating
heating
| Time | AtomicLineEmission Cooling | H2CollisionallyInduced Cooling | Compton Cooling | ContinuumEmission Cooling | MolecularLine Cooling | H Line Cooling | C+ Line Cooling | O Line Cooling | C Line Cooling | ... | PhotoelectricBakes Heating | PhotoelectricWeingartner Heating | H2Formation Heating | H2Photodissociation Heating | H2FUVPumping Heating | CarbonIonization Heating | CosmicRay Heating | Turbulent Heating | GasGrainCollisions Heating | Chemical Heating | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1.000000e-07 | 0.0 | 0.0 | 7.487719e-35 | 2.985107e-63 | 1.166008e-24 | 0.0 | 0.0 | 3.310983e-25 | 8.348479e-25 | ... | -1.100196e-34 | 0.0 | 3.755034e-21 | 0.0 | 0.0 | 4.513450e-48 | 1.041415e-24 | 7.000000e-40 | 0.000000e+00 | 0.0 |
| 1 | 1.000000e-06 | 0.0 | 0.0 | 7.487719e-35 | 2.985107e-63 | 1.165998e-24 | 0.0 | 0.0 | 3.310983e-25 | 8.348376e-25 | ... | -1.100196e-34 | 0.0 | 3.755034e-21 | 0.0 | 0.0 | 4.515769e-48 | 3.030519e-24 | 7.000000e-40 | -9.310917e-34 | 0.0 |
| 2 | 1.000000e-05 | 0.0 | 0.0 | 7.487720e-35 | 2.985108e-63 | 1.166017e-24 | 0.0 | 0.0 | 3.310984e-25 | 8.348549e-25 | ... | -1.100196e-34 | 0.0 | 3.755034e-21 | 0.0 | 0.0 | 4.536644e-48 | 3.030519e-24 | 7.000000e-40 | -9.315356e-33 | 0.0 |
| 3 | 1.000000e-04 | 0.0 | 0.0 | 7.487720e-35 | 2.985108e-63 | 1.166017e-24 | 0.0 | 0.0 | 3.310997e-25 | 8.348518e-25 | ... | -1.100196e-34 | 0.0 | 3.755034e-21 | 0.0 | 0.0 | 4.745404e-48 | 3.030519e-24 | 7.000000e-40 | -9.315801e-32 | 0.0 |
| 4 | 1.000000e-03 | 0.0 | 0.0 | 7.487723e-35 | 2.985113e-63 | 1.166047e-24 | 0.0 | 0.0 | 3.311123e-25 | 8.348392e-25 | ... | -1.100197e-34 | 0.0 | 3.755034e-21 | 0.0 | 0.0 | 6.833985e-48 | 3.030519e-24 | 7.000000e-40 | -9.315847e-31 | 0.0 |
| 5 | 1.000000e-02 | 0.0 | 0.0 | 7.487753e-35 | 2.985165e-63 | 1.166447e-24 | 0.0 | 0.0 | 3.312383e-25 | 8.348272e-25 | ... | -1.100209e-34 | 0.0 | 3.755033e-21 | 0.0 | 0.0 | 2.780588e-47 | 3.030519e-24 | 7.000000e-40 | -9.315871e-30 | 0.0 |
| 6 | 1.000000e-01 | 0.0 | 0.0 | 7.488048e-35 | 2.985680e-63 | 1.170624e-24 | 0.0 | 0.0 | 3.324984e-25 | 8.348308e-25 | ... | -1.100331e-34 | 0.0 | 3.755032e-21 | 0.0 | 0.0 | 2.406090e-46 | 3.030519e-24 | 7.000000e-40 | -9.316070e-29 | 0.0 |
| 7 | 1.000000e+00 | 0.0 | 0.0 | 7.490966e-35 | 2.990834e-63 | 1.212569e-24 | 0.0 | 0.0 | 3.453174e-25 | 8.349198e-25 | ... | -1.101548e-34 | 0.0 | 3.755022e-21 | 0.0 | 0.0 | 2.374056e-45 | 3.030524e-24 | 7.000000e-40 | -9.318054e-28 | 0.0 |
| 8 | 1.000000e+01 | 0.0 | 0.0 | 7.759661e-35 | 3.506024e-63 | 4.150609e-24 | 0.0 | 0.0 | 1.574924e-24 | 8.431027e-25 | ... | -1.219336e-34 | 0.0 | 3.821641e-21 | 0.0 | 0.0 | 1.880749e-43 | 3.031307e-24 | 7.000000e-40 | -8.135891e-26 | 0.0 |
| 9 | 1.000000e+02 | 0.0 | 0.0 | 1.055043e-34 | 1.601465e-62 | 3.574683e-23 | 0.0 | 0.0 | 2.009385e-23 | 9.058431e-25 | ... | -3.175190e-34 | 0.0 | 4.492683e-21 | 0.0 | 0.0 | 1.383387e-42 | 3.039901e-24 | 7.000000e-40 | -1.244761e-24 | 0.0 |
| 10 | 2.000000e+02 | 0.0 | 0.0 | 1.400875e-34 | 6.085257e-62 | 1.135321e-22 | 0.0 | 0.0 | 7.100815e-23 | 5.470146e-24 | ... | -7.343722e-34 | 0.0 | 5.138866e-21 | 0.0 | 0.0 | 1.101764e-42 | 3.049794e-24 | 7.000000e-40 | -3.113675e-24 | 0.0 |
| 11 | 3.000000e+02 | 0.0 | 0.0 | 1.757610e-34 | 1.811043e-61 | 3.515446e-22 | 0.0 | 0.0 | 2.358660e-22 | 4.441004e-23 | ... | -1.443247e-33 | 0.0 | 5.695782e-21 | 0.0 | 0.0 | 9.324994e-43 | 3.060225e-24 | 7.000000e-40 | -5.500991e-24 | 0.0 |
| 12 | 4.000000e+02 | 0.0 | 0.0 | 2.105001e-34 | 4.446628e-61 | 7.458767e-22 | 0.0 | 0.0 | 4.532101e-22 | 1.789472e-22 | ... | -2.496413e-33 | 0.0 | 6.163665e-21 | 0.0 | 0.0 | 8.203232e-43 | 3.071104e-24 | 7.000000e-40 | -8.215717e-24 | 0.0 |
| 13 | 5.000000e+02 | 0.0 | 0.0 | 2.407529e-34 | 8.920321e-61 | 1.306477e-21 | 0.0 | 0.0 | 7.266848e-22 | 4.213907e-22 | ... | -3.793595e-33 | 0.0 | 6.523852e-21 | 0.0 | 0.0 | 7.333908e-43 | 3.081609e-24 | 7.000000e-40 | -1.087112e-23 | 0.0 |
| 14 | 6.000000e+02 | 0.0 | 0.0 | 2.661447e-34 | 1.556181e-60 | 2.158357e-21 | 0.0 | 0.0 | 1.067836e-21 | 8.894247e-22 | ... | -5.270724e-33 | 0.0 | 6.803286e-21 | 0.0 | 0.0 | 6.677252e-43 | 3.092336e-24 | 7.000000e-40 | -1.338619e-23 | 0.0 |
| 15 | 7.000000e+02 | 0.0 | 0.0 | 2.854768e-34 | 2.397368e-60 | 3.159351e-21 | 0.0 | 0.0 | 1.384716e-21 | 1.530278e-21 | ... | -6.769924e-33 | 0.0 | 7.009663e-21 | 0.0 | 0.0 | 6.179980e-43 | 3.103177e-24 | 7.000000e-40 | -1.560455e-23 | 0.0 |
| 16 | 8.000000e+02 | 0.0 | 0.0 | 2.978954e-34 | 3.301719e-60 | 4.100755e-21 | 0.0 | 0.0 | 1.647955e-21 | 2.169177e-21 | ... | -8.107446e-33 | 0.0 | 7.151321e-21 | 0.0 | 0.0 | 5.800996e-43 | 3.114127e-24 | 7.000000e-40 | -1.740943e-23 | 0.0 |
| 17 | 9.000000e+02 | 0.0 | 0.0 | 3.044740e-34 | 4.146650e-60 | 4.851508e-21 | 0.0 | 0.0 | 1.848526e-21 | 2.687133e-21 | ... | -9.178149e-33 | 0.0 | 7.242572e-21 | 0.0 | 0.0 | 5.504575e-43 | 3.124652e-24 | 7.000000e-40 | -1.878358e-23 | 0.0 |
| 18 | 1.000000e+03 | 0.0 | 0.0 | 3.067780e-34 | 4.905845e-60 | 5.435084e-21 | 0.0 | 0.0 | 1.996990e-21 | 3.095256e-21 | ... | -1.001629e-32 | 0.0 | 7.301227e-21 | 0.0 | 0.0 | 5.272374e-43 | 3.135140e-24 | 7.000000e-40 | -1.984741e-23 | 0.0 |
| 19 | 2.000000e+03 | 0.0 | 0.0 | 2.467887e-34 | 7.783575e-60 | 7.158947e-21 | 0.0 | 0.0 | 2.241113e-21 | 4.432453e-21 | ... | -1.141973e-32 | 0.0 | 7.266573e-21 | 0.0 | 0.0 | 6.011086e-43 | 3.236002e-24 | 7.000000e-40 | -2.299937e-23 | 0.0 |
| 20 | 3.000000e+03 | 0.0 | 0.0 | 1.820954e-34 | 8.009917e-60 | 6.976409e-21 | 0.0 | 0.0 | 1.989355e-21 | 4.428172e-21 | ... | -1.009954e-32 | 0.0 | 7.026947e-21 | 0.0 | 0.0 | 4.493836e-43 | 3.334018e-24 | 7.000000e-40 | -2.320682e-23 | 0.0 |
| 21 | 4.000000e+03 | 0.0 | 0.0 | 1.372166e-34 | 8.246560e-60 | 6.741901e-21 | 0.0 | 0.0 | 1.737476e-21 | 4.386935e-21 | ... | -9.017462e-33 | 0.0 | 6.808183e-21 | 0.0 | 0.0 | 3.866661e-43 | 3.423660e-24 | 7.000000e-40 | -2.341900e-23 | 0.0 |
| 22 | 5.000000e+03 | 0.0 | 0.0 | 9.670979e-35 | 8.646406e-60 | 6.471724e-21 | 0.0 | 0.0 | 1.433629e-21 | 4.354515e-21 | ... | -7.879750e-33 | 0.0 | 6.552151e-21 | 0.0 | 0.0 | 3.506612e-43 | 3.530211e-24 | 7.000000e-40 | -2.376720e-23 | 0.0 |
| 23 | 6.000000e+03 | 0.0 | 0.0 | 7.343128e-35 | 9.009782e-60 | 6.282857e-21 | 0.0 | 0.0 | 1.215406e-21 | 4.337732e-21 | ... | -7.097726e-33 | 0.0 | 6.364602e-21 | 0.0 | 0.0 | 3.247799e-43 | 3.608807e-24 | 7.000000e-40 | -2.407316e-23 | 0.0 |
| 24 | 7.000000e+03 | 0.0 | 0.0 | 5.236676e-35 | 9.366566e-60 | 6.087725e-21 | 0.0 | 0.0 | 9.824387e-22 | 4.327748e-21 | ... | -6.206339e-33 | 0.0 | 6.152176e-21 | 0.0 | 0.0 | 3.077879e-43 | 3.696188e-24 | 7.000000e-40 | -2.436455e-23 | 0.0 |
| 25 | 8.000000e+03 | 0.0 | 0.0 | 3.483939e-35 | 9.690435e-60 | 5.873014e-21 | 0.0 | 0.0 | 7.596486e-22 | 4.288640e-21 | ... | -5.245737e-33 | 0.0 | 5.927502e-21 | 0.0 | 0.0 | 2.960742e-43 | 3.787153e-24 | 7.000000e-40 | -2.462183e-23 | 0.0 |
| 26 | 9.000000e+03 | 0.0 | 0.0 | 2.364401e-35 | 9.907898e-60 | 5.693158e-21 | 0.0 | 0.0 | 6.021007e-22 | 4.232427e-21 | ... | -4.448098e-33 | 0.0 | 5.747900e-21 | 0.0 | 0.0 | 2.877779e-43 | 3.858925e-24 | 7.000000e-40 | -2.479093e-23 | 0.0 |
| 27 | 1.000000e+04 | 0.0 | 0.0 | 1.453536e-35 | 1.012338e-59 | 5.505157e-21 | 0.0 | 0.0 | 4.645704e-22 | 4.151556e-21 | ... | -3.604903e-33 | 0.0 | 5.569542e-21 | 0.0 | 0.0 | 2.820920e-43 | 3.929932e-24 | 7.000000e-40 | -2.495572e-23 | 0.0 |
| 28 | 2.000000e+04 | 0.0 | 0.0 | 4.204058e-39 | 9.139427e-60 | 3.878880e-21 | 0.0 | 0.0 | 1.305229e-23 | 2.890876e-21 | ... | -8.653598e-35 | 0.0 | 3.856126e-21 | 0.0 | 0.0 | 2.441808e-43 | 4.575572e-24 | 7.000000e-40 | -2.418004e-23 | 0.0 |
| 29 | 3.000000e+04 | 0.0 | 0.0 | 3.484861e-39 | 6.895284e-60 | 2.675511e-21 | 0.0 | 0.0 | 4.759183e-24 | 1.749193e-21 | ... | -7.126339e-35 | 0.0 | 2.638103e-21 | 0.0 | 0.0 | 2.469465e-43 | 5.025666e-24 | 7.000000e-40 | -2.213788e-23 | 0.0 |
| 30 | 4.000000e+04 | 0.0 | 0.0 | 3.234427e-39 | 4.832719e-60 | 1.832680e-21 | 0.0 | 0.0 | 2.572568e-24 | 1.021949e-21 | ... | -5.998565e-35 | 0.0 | 1.795690e-21 | 0.0 | 0.0 | 2.673782e-43 | 5.338339e-24 | 7.000000e-40 | -1.975061e-23 | 0.0 |
| 31 | 5.000000e+04 | 0.0 | 0.0 | 3.040223e-39 | 3.376957e-60 | 1.272224e-21 | 0.0 | 0.0 | 1.534769e-24 | 5.831385e-22 | ... | -5.067806e-35 | 0.0 | 1.223275e-21 | 0.0 | 0.0 | 2.890581e-43 | 5.554960e-24 | 7.000000e-40 | -1.754193e-23 | 0.0 |
| 32 | 6.000000e+04 | 0.0 | 0.0 | 2.790441e-39 | 2.149618e-60 | 8.669902e-22 | 0.0 | 0.0 | 9.213588e-25 | 3.233932e-22 | ... | -4.078814e-35 | 0.0 | 8.210216e-22 | 0.0 | 0.0 | 3.060460e-43 | 5.708481e-24 | 7.000000e-40 | -1.502153e-23 | 0.0 |
| 33 | 7.000000e+04 | 0.0 | 0.0 | 2.516961e-39 | 1.373554e-60 | 5.982514e-22 | 0.0 | 0.0 | 5.672829e-25 | 1.734893e-22 | ... | -3.258633e-35 | 0.0 | 5.519997e-22 | 0.0 | 0.0 | 3.211900e-43 | 5.814173e-24 | 7.000000e-40 | -1.278964e-23 | 0.0 |
| 34 | 8.000000e+04 | 0.0 | 0.0 | 2.242211e-39 | 8.855227e-61 | 4.042568e-22 | 0.0 | 0.0 | 3.495755e-25 | 7.468949e-23 | ... | -2.595692e-35 | 0.0 | 3.679853e-22 | 0.0 | 0.0 | 3.297568e-43 | 5.888991e-24 | 7.000000e-40 | -1.084044e-23 | 0.0 |
| 35 | 9.000000e+04 | 0.0 | 0.0 | 1.995400e-39 | 5.752553e-61 | 2.916422e-22 | 0.0 | 0.0 | 2.215726e-25 | 3.747202e-23 | ... | -2.070925e-35 | 0.0 | 2.459149e-22 | 0.0 | 0.0 | 3.314728e-43 | 5.940267e-24 | 7.000000e-40 | -9.137865e-24 | 0.0 |
| 36 | 1.000000e+05 | 0.0 | 0.0 | 1.718757e-39 | 3.377529e-61 | 2.064114e-22 | 0.0 | 0.0 | 1.316863e-25 | 2.313840e-23 | ... | -1.561223e-35 | 0.0 | 1.638731e-22 | 0.0 | 0.0 | 3.280947e-43 | 5.975159e-24 | 7.000000e-40 | -7.304371e-24 | 0.0 |
| 37 | 2.000000e+05 | 0.0 | 0.0 | 8.999688e-40 | 1.201838e-62 | 1.454990e-23 | 0.0 | 0.0 | 7.415171e-27 | 9.396016e-26 | ... | -2.845361e-36 | 0.0 | 3.770210e-24 | 0.0 | 0.0 | 5.099910e-44 | 6.052441e-24 | 7.000000e-40 | -9.600920e-25 | 0.0 |
| 38 | 3.000000e+05 | 0.0 | 0.0 | 5.359658e-40 | 6.879358e-63 | 6.778661e-24 | 0.0 | 0.0 | 8.819628e-27 | 5.280131e-26 | ... | -1.786389e-36 | 0.0 | 7.076531e-25 | 0.0 | 0.0 | 1.438185e-44 | 6.054109e-24 | 7.000000e-40 | -5.000709e-25 | 0.0 |
| 39 | 4.000000e+05 | 0.0 | 0.0 | 5.659641e-40 | 6.440042e-63 | 6.199081e-24 | 0.0 | 0.0 | 1.091460e-26 | 3.836571e-26 | ... | -1.772020e-36 | 0.0 | 5.561210e-25 | 0.0 | 0.0 | 1.476274e-44 | 6.054055e-24 | 7.000000e-40 | -4.529640e-25 | 0.0 |
| 40 | 5.000000e+05 | 0.0 | 0.0 | 6.399018e-40 | 6.397197e-63 | 6.057769e-24 | 0.0 | 0.0 | 1.448423e-26 | 3.022693e-26 | ... | -1.857734e-36 | 0.0 | 5.326686e-25 | 0.0 | 0.0 | 1.606737e-44 | 6.053935e-24 | 7.000000e-40 | -4.482787e-25 | 0.0 |
| 41 | 6.000000e+05 | 0.0 | 0.0 | 9.164150e-40 | 6.878532e-63 | 5.882461e-24 | 0.0 | 0.0 | 2.288786e-26 | 1.689517e-26 | ... | -2.223251e-36 | 0.0 | 5.313387e-25 | 0.0 | 0.0 | 1.519789e-44 | 6.053515e-24 | 7.000000e-40 | -4.999839e-25 | 0.0 |
| 42 | 7.000000e+05 | 0.0 | 0.0 | 1.191312e-39 | 7.337220e-63 | 5.807951e-24 | 0.0 | 0.0 | 2.361776e-26 | 1.299020e-26 | ... | -2.546136e-36 | 0.0 | 5.351541e-25 | 0.0 | 0.0 | 1.320935e-44 | 6.053298e-24 | 7.000000e-40 | -5.474699e-25 | 0.0 |
| 43 | 8.000000e+05 | 0.0 | 0.0 | 1.871863e-39 | 8.073298e-63 | 5.716142e-24 | 0.0 | 0.0 | 2.403425e-26 | 9.700345e-27 | ... | -3.188680e-36 | 0.0 | 5.418687e-25 | 0.0 | 0.0 | 1.124983e-44 | 6.053076e-24 | 7.000000e-40 | -6.204216e-25 | 0.0 |
| 44 | 9.000000e+05 | 0.0 | 0.0 | 2.665854e-39 | 8.603579e-63 | 5.637955e-24 | 0.0 | 0.0 | 2.404294e-26 | 8.219155e-27 | ... | -3.779656e-36 | 0.0 | 5.467853e-25 | 0.0 | 0.0 | 1.035242e-44 | 6.052969e-24 | 7.000000e-40 | -6.707517e-25 | 0.0 |
45 rows × 23 columns
Plotting Individual Heating and Cooling Contributions#
Let’s visualize the dominant heating and cooling processes over time.
fig, axes = plt.subplots(2, 1, figsize=(12, 10))
# Plot heating processes
time = physics["Time"]
for col in heating_cols:
# Only plot processes with significant contribution
max_val = heating[col].abs().max()
if max_val > 1e-30: # Filter out negligible contributions
label = col.replace("_heating", "").replace("_", " ")
axes[0].plot(time, heating[col], label=label, linewidth=2, alpha=0.7)
axes[0].set_xlabel("Time (years)", fontsize=12)
axes[0].set_ylabel("Heating Rate (erg cm⁻³ s⁻¹)", fontsize=12)
axes[0].set_xscale("log")
axes[0].set_yscale("symlog", linthresh=1e-30)
axes[0].set_title("Heating Processes", fontsize=14)
axes[0].legend(fontsize=8, loc="best")
axes[0].grid(True, alpha=0.3)
# Plot cooling processes (select major ones to avoid cluttering)
for col in cooling_cols:
max_val = heating[col].abs().max()
if max_val > 1e-40:
label = col.replace("_cooling", "").replace("_", " ")
axes[1].plot(time, heating[col], label=label, linewidth=2, alpha=0.7)
axes[1].set_xlabel("Time (years)", fontsize=12)
axes[1].set_ylabel("Cooling Rate (erg cm⁻³ s⁻¹)", fontsize=12)
axes[1].set_xscale("log")
axes[1].set_yscale("symlog", linthresh=1e-30)
axes[1].set_title("Major Cooling Processes", fontsize=14)
axes[1].legend(fontsize=8, loc="best")
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
Example 4: Writing Heating Rates to a File#
You can also save heating and cooling rates directly to a file during the model run using the heatingFile parameter. This requires not running any other cells to memory before!
# You can uncomment the cel below to run a model to disk.
# # Run model with heating file output
# param_dict_with_file = param_dict_heating.copy()
# param_dict_with_file["outputFile"] = "../examples/test-output/heating_demo.dat"
# param_dict_with_file["heatingFile"] = "../examples/test-output/heating_rates.dat"
# result = uclchem.model.cloud(
# param_dict=param_dict_with_file, out_species=["CO", "H2O", "OH"]
# )
# print(f"Model completed with flag: {result[0]}")
# print(f"Final CO abundance: {result[1]:.2e}")
# print(f"Final H2O abundance: {result[2]:.2e}")
# print(f"Final OH abundance: {result[3]:.2e}")
# # Read the heating file
# if os.path.exists("../examples/test-output/heating_rates.dat"):
# print("\nHeating rates file created successfully!")
# heating_df = pd.read_csv("../examples/test-output/heating_rates.dat")
# print(f"File contains {len(heating_df)} time steps")
# print(f"Columns: {heating_df.columns.tolist()[:10]}...") # Show first 10 columns
Example 5: Different Physical Conditions#
Let’s explore how heating and cooling behave under different physical conditions. We’ll compare a dense, cold core with a less dense, warmer environment.
# Dense, cold core (like Example 1)
param_cold_core = {
"initialDens": 1e5,
"initialTemp": 10.0,
"finalTime": 1.0e6,
"baseAv": 20.0,
"rout": 0.05,
"freefall": False,
"heatingFlag": True,
}
# Less dense, warmer cloud
param_warm_cloud = {
"initialDens": 1e3,
"initialTemp": 30.0,
"finalTime": 1.0e6,
"baseAv": 5.0,
"rout": 0.5,
"freefall": False,
"heatingFlag": True,
}
# Run both models
print("Running cold core model...")
cloud_cold = uclchem.model.Cloud(param_dict=param_cold_core)
phys_cold, abund_cold = cloud_cold.get_dataframes(joined=False)
_, _, rates_cold = cloud_cold.get_dataframes(joined=False, with_rates=True)
_, _, heating_cold = cloud_cold.get_dataframes(joined=False, with_heating=True)
flag_cold = 0 if cloud_cold.has_attr("_data") else -1
print("Running warm cloud model...")
cloud_warm = uclchem.model.Cloud(param_dict=param_warm_cloud)
phys_warm, abund_warm = cloud_warm.get_dataframes(joined=False)
_, _, rates_warm = cloud_warm.get_dataframes(joined=False, with_rates=True)
_, _, heating_warm = cloud_warm.get_dataframes(joined=False, with_heating=True)
flag_warm = 0 if cloud_warm.has_attr("_data") else -1
print(f"\nCold core flag: {flag_cold}, Warm cloud flag: {flag_warm}")
# Compare temperature evolution
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
axes[0].plot(
phys_cold["Time"],
phys_cold["gasTemp"],
label=f"Dense Core (n={param_cold_core['initialDens']:.0e})",
linewidth=2,
)
axes[0].plot(
phys_warm["Time"],
phys_warm["gasTemp"],
label=f"Diffuse Cloud (n={param_warm_cloud['initialDens']:.0e})",
linewidth=2,
)
axes[0].set_xlabel("Time (years)", fontsize=12)
axes[0].set_ylabel("Gas Temperature (K)", fontsize=12)
axes[0].set_xscale("log")
axes[0].set_title("Temperature Evolution", fontsize=14)
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# Compare CO abundance
axes[1].plot(phys_cold["Time"], abund_cold["CO"], label="Dense Core", linewidth=2)
axes[1].plot(phys_warm["Time"], abund_warm["CO"], label="Diffuse Cloud", linewidth=2)
axes[1].set_xlabel("Time (years)", fontsize=12)
axes[1].set_ylabel("CO Abundance", fontsize=12)
axes[1].set_xscale("log")
axes[1].set_yscale("log")
axes[1].set_title("CO Abundance", fontsize=14)
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
print("\nFinal temperatures:")
print(f" Cold core: {phys_cold['gasTemp'].iloc[-1]:.2f} K")
print(f" Warm cloud: {phys_warm['gasTemp'].iloc[-1]:.2f} K")
Running cold core model...
Running warm cloud model...
Cold core flag: -1, Warm cloud flag: -1
Final temperatures:
Cold core: 11.06 K
Warm cloud: 20.32 K
Summary of Key Heating and Cooling Processes#
UCLCHEM includes the following heating and cooling mechanisms:
Major Heating Processes:#
Photoelectric heating - from PAHs and dust grains (Bakes & Tielens 1994)
H₂ formation heating - energy released during H₂ formation on grains
H₂ photodissociation heating - kinetic energy from photodissociation
Cosmic ray heating - direct and indirect (via ionization)
Chemical reaction enthalpy - exothermic reactions (optional, requires network configuration)
X-ray heating - in environments with X-ray sources
Turbulent heating - dissipation of turbulent energy
Viscous heating - for shock models
Major Cooling Processes:#
Molecular line cooling - CO, H₂O, OH, and other molecules
Atomic fine structure cooling - C⁺, O, C, etc.
Dust continuum cooling - gas-grain collisional cooling
H₂ line cooling - rovibrational transitions
Recombination cooling - electronic to kinetic energy
Ly-α cooling - Lyman-alpha photon emission
Key Parameters:#
heatingFlag: Enable/disable all heating processes (default:True)heatingFile: Path to write detailed heating/cooling ratesinitialTemp: Starting gas temperaturebaseAv: Visual extinction (affects radiation field attenuation)zeta: Cosmic ray ionization rate
For a complete list of processes and their equations, see the HEATING_COOLING_SUMMARY.md documentation file.
Advanced: Chemical Reaction Enthalpy#
UCLCHEM can optionally include the enthalpy changes from chemical reactions as a heating/cooling source. This requires configuring the chemical network at build time using MakeRates.
Note: This feature requires rebuilding UCLCHEM with specific settings in the user_settings.yaml file. The main settings are:
add_delta_enthalpy: Can beFalse,GAS, orALLFalse: No reaction enthalpy (default)GAS: Include enthalpy from gas-phase reactions onlyALL: Include enthalpy from all reactions (gas + surface)
To enable reaction enthalpy:
# In Makerates/user_settings.yaml
add_delta_enthalpy: GAS
Then rebuild:
cd Makerates
python MakeRates.py
cd ..
pip install .
For more details, see the heating_cooling_benchmarks/ directory which contains examples with different enthalpy configurations.
Tips for Using Heating and Cooling#
Always check convergence: Use
return_dataframe=Trueand inspect temperature evolution to ensure physical resultsMonitor element conservation: Use
uclchem.analysis.check_element_conservation()to verify model accuracySave heating rates for analysis: Use
heatingFileparameter to save detailed heating/cooling contributionsChoose appropriate tolerances: If you see unphysical temperature spikes, try adjusting
reltolandabstolparametersConsider your environment: Different astrophysical environments have different dominant heating/cooling processes:
Dense cores: Line cooling (CO, H₂O) dominates
Diffuse clouds: Photoelectric heating and fine-structure cooling
Shock regions: Viscous/turbulent heating important
PDRs: Strong FUV field means photoelectric heating dominates
Radiation field matters: The
baseAvparameter controls UV attenuation, which significantly affects photoelectric heating and photodissociation rates
Next Steps#
Check out 7_heating_cooling_settings.ipynb for more advanced configuration options
See
HEATING_COOLING_SUMMARY.mdfor detailed equations and referencesExplore the
heating_cooling_benchmarks/directory for systematic comparisons