Ch 6. Ozone Isopleth

OVERVIEW

    • At this point you are already an expert on box model! We will now spice things up!
    • Ozone plays a key role in Earth's atmosphere. The ozone layer in the stratosphere filters out the harmful UV radiation from the sunlight. Ozone is also a major source of HOx radicals which largely controlls the self-cleaning capacity of the atmosphere. At the ground-level, ozone is also a pollutant that can cause a bunch of health issues.
    • In the troposphere, ozone is produced from photochemistry involving volatile organic compounds (VOCs) and NOx, and both VOCs and NOx are emitted from a variety of natural and anthropogenic sources. In urban areas, to effectively control ambient ozone levels, people need to reduce VOCs and NOx. However, in different places the story may be completely different. What is the most efficient way to reduce ambient ozone levels?
    • The concept of ozone isopleth, or EKMA plot, is a useful way to decide what may be the more efficient ozone control strategy. The idea is to run the model with different conditions (VOCs and NOx) to see what's the maximum ozone formation potential looks like. Therefore you have to set up the model, and run the model many, many, times.

1. VOC-NOx MECHANISM?

  • Go to the MCM website to download the KPP file (don't forget to include inorganic reactions too).
  • MCM contains near-explicit oxidation pathways of tens of major VOC species (tens of thousands of reactions perhaps), and all of them contribute to O3 formation in the atmosphere. You probably don't need the full mechanism. You need to decide what information you have access to. Unnecessarily complicated mechanism means excessive computational burden, and the results may not be "more correct".
  • Usually for urban environments, I would mark C1-C5 alkanes, C2 alkenes and alkyne, benzene, toluene, xylenes, isoprene, and a-/b-pinenes. These should be sufficient for most ambient conditions. Mechanism like this would have more than 10k reactions and hence it will run slow, and in this example, it would be awful as we have to run the model many times.
  • For the sake of simplicity, in this example I'll use a relatively small subset of MCM with C1-C4 alkanes + isoprene only, with 4.5k reactions.

2. EXPERIMENT DESIGN

  • There are many ways to do the ozone isopleth. In this example we run it in a very simple way.
  • Firstly let's make "value pools" for the initial NOx and VOCs. Then we will loop thru each possible combination, send into the model, run for 3 days, and output results every 3 hours. Then pick the max O3 over the course of these 3 days. Once it's all done, we'll make the contour showing the max O3 as a function of initial NOx and VOCs.
  • During these 3 days, again for simplicity, let's set environment conditions constant: T = 298 K, SZA = 20 deg, RH = 60. The reason that l ask the model to run for 3 days is that, under this conditions the NOx lifetime is probably a few days. If you are running out of NOx, you're not going to make any more O3.
  • If you want you can set up diurnal variations etc to make it a bit more realistic, be my guest ;)
  • Alternatively, people sometimes vary NOx and VOC emission rates, instead of initial concentrations as we do here. Well, you know how to deal with emissions ;) Feel free to give it a shot.

3. MODEL SETUP

  • I wrote this function, in which the model will be called / ran many times:

Function Shell() Make/O pool_ScalingFactor_NO = {0.1, 0.3, 1, 3, 10} Make/O pool_ScalingFactor_AVOCs = {0.1, 0.3, 1, 3, 10} Make/O/N=(DimSize(pool_ScalingFactor_NO,0)*DimSize(pool_ScalingFactor_AVOCs,0)) NO_ppb = nan Make/O/N=(DimSize(pool_ScalingFactor_NO,0)*DimSize(pool_ScalingFactor_AVOCs,0)) TNMHCs_ppb = nan Make/O/N=(DimSize(pool_ScalingFactor_NO,0)*DimSize(pool_ScalingFactor_AVOCs,0)) O3_max_ppb = nan Variable i, j, n Variable ScalingFactor_NO, ScalingFactor_AVOCs For (i=0; i<DimSize(pool_ScalingFactor_NO,0); i+=1) For (j=0; j<DimSize(pool_ScalingFactor_AVOCs,0); j+=1) ScalingFactor_NO = pool_ScalingFactor_NO[i] ScalingFactor_AVOCs = pool_ScalingFactor_AVOCs[j] Print num2str(n) + " out of " + num2str(-1+DimSize(NO_ppb,0)) Sim1(n, ScalingFactor_NO, ScalingFactor_AVOCs) // Run the model n = n + 1 Endfor Endfor End
  • Copy-paste this into the procedure window. Here's what it does: firstly it makes two pools for the scaling factors for NO and AVOCs (anthropogenic). They both range from 0.1 to 10. You may expand these to ranges if you want.
  • In this example the scaling factor for AVOCs is only applied to anthropogenic non-methane hydrocarbons, as you can't yelling at trees and be like "hey stop emitting those damn biogenic VOCs"!
  • Then three empty waves are made: NO_ppb and TNMHCs_ppb are for the initial conditions and O3_max_ppb is for, well, max O3 over the course of the 3 days of simulation. Then a simulation index (n), and the scaling factors of NO and AVOCs are passed into the model: Sim1(n, ScalingFactor_NO, ScalingFactor_AVOC).
  • It should look something like this screenshot.
  • You'll have to modify the Sim() a little as well, to accommodate the three parameters passed into this function. Fairly simple.
  • Set the initial concentrations, with scaling factors applied to NO and anthropogenic VOCs. Remember where should we set the initial concentrations? The codes are here:

Concentration_Matrix[0][724] = ScalingFactor_NO * 10*Pressure*(6.0232E+8)/(8.314*TEMP) // NO Concentration_Matrix[0][1048] = 30*Pressure*(6.0232E+8)/(8.314*TEMP) // O3 Concentration_Matrix[0][262] = 150*Pressure*(6.0232E+8)/(8.314*TEMP) // CO Concentration_Matrix[0][119] = 2000*Pressure*(6.0232E+8)/(8.314*TEMP) // CH4 Concentration_Matrix[0][1338] = ScalingFactor_AVOCs * 5*Pressure*(6.0232E+8)/(8.314*TEMP) // C2H6 Concentration_Matrix[0][1329] = ScalingFactor_AVOCs * 2*Pressure*(6.0232E+8)/(8.314*TEMP) // C3H8 Concentration_Matrix[0][494] = ScalingFactor_AVOCs * 1*Pressure*(6.0232E+8)/(8.314*TEMP) // i-C4H10 Concentration_Matrix[0][596] = ScalingFactor_AVOCs * 1*Pressure*(6.0232E+8)/(8.314*TEMP) // n-C4H10 Concentration_Matrix[0][1293] = 1*Pressure*(6.0232E+8)/(8.314*TEMP) // isoprene
  • You also need to edit the very end of Sim(...), to pass the intial NO and total non-methane hydrocarbons to NO_ppb and TNMHCs_ppb, respectively. Also maximum O3 (except for the first datapoint) to O3_max_ppb.

Make/O/N=(DimSize(Concentration_Matrix,0)) O3_TEMP = Concentration_Matrix[p][1048] O3_TEMP[0] = nan Variable convert_molec_cm3_to_ppb = 1 / (Pressure*(6.0232E+8)/(8.314*TEMP)) Wave NO_ppb, TNMHCs_ppb, O3_max_ppb NO_ppb[index] = Concentration_Matrix[0][724] * convert_molec_cm3_to_ppb TNMHCs_ppb[index] = (Concentration_Matrix[0][1338]+Concentration_Matrix[0][1329]+ Concentration_Matrix[0][494]+Concentration_Matrix[0][596]+Concentration_Matrix[0][1293]) * convert_molec_cm3_to_ppb Variable v_max = nan WaveStats/Q O3_TEMP O3_max_ppb[index] = v_max * convert_molec_cm3_to_ppb KillWaves O3_TEMP
  • It should look something like the screenshot below. Right before the End.

4. NOW LET'S ROLL!

  • ... wait just one second. Since you touched Sim1(...) and now it has three input parameters, all other functions / macros calling Sim1(...) will surely complain. In the GUI I have a button whose procedure calls the original Sim1(), i.e. without those inputs. To fix this, simply comment it out or delete the line in which Sim1() is called.
  • Now in the command line, run shell()!!!
  • In this example the model will run for 25 times! So it will take a while. If you use more complicated chemistry, or if your scaling factor waves are expended, it will take even longer. Go grab a coffee and pet your cat - whatever you do, leave IGOR alone.

5. MAKE THE CONTOUR

  • Once it's done, you can make the contour plot. Click Windows - New - Contour plot, then this dialog will pop out. Select the three waves we just made.
  • The raw contour looks ugly. Make it prettier.

6. OZONE ISOPLETH

  • Here's my example. Because we only have 25 datapoints, the contour lines are not smooth. But it makes sense:
  • Look at the top left corner: in this region, the more NOx you have, the less O3 you got. This is because VOC levels are too low to make any new O3, but the large amount of fresh NO would quickly consume O3 to make NO2. This is often referred to as "NO titration" regime. In this regime, the sum of O3 and NO2 wouldn't change much but O3 would decrease with increasing NO.
  • Still in the top left side but below the NO titration regime, where you have quite some NOx but low VOC. In this regime O3 formation is sensitive to VOCs but less so for NOx. This is call "VOC sensitive regime".
  • The top right corner has the highest O3, because you got both ingredients.
  • The bottom right corner is interesting, where VOCs are high but NOx is low. In this regime O3 formation is very sensitive to NOx levels but less sensitive to VOC levels. This is often called NOx sensitive regime.

7. SUMMARY

  • In this chapter we demonstrated that sometimes it can be quite useful to run the model many times in a systematic manner. We also learnt about ozone isopleth and different ozone formation sensitivity regimes. If you have your own ambient measurements, especially VOCs, you may make the ozone isopleth based on your condition!
  • Again there are multiple ways to construct the ozone isopleth. For example, you may vary emissions (instead of initial concentrations like we did in this example); you may also set diurnal variations; in this example we perturb anthropogenic non-methane hydrocarbons, but in reality the perturbation may occur differently, i.e. perhaps CH4, OVOCs, CO would vary as well.