MAXDCONT: who caused the high value
A cumulative demonstration fails. The modeled design value, with every nearby source and background included, sits above the standard. The next question is not "how do we lower it" — it is "whose concentration is that?"
Answering it is harder than it sounds, and the difficulty is created by the form of the modern standards themselves. A design value based on the eighth-highest daily maximum, averaged over five years, is not an event. It is a statistic assembled from forty different hours at potentially forty different times. There is no single moment to look at, so "the neighbor's share of the design value" has to be defined carefully — and computed by the model, paired in time and space, rather than estimated by hand.
MAXDCONT is the tool AERMOD provides for exactly this. The User's Guide is explicit about why it exists:
Beginning with version 11059, three output options have been incorporated on the OU pathway to support the 1-hour NO2 and SO2 standards, especially the analyses that may be required to determine a source's (or group of sources) contributions to modeled violations of the NAAQS for comparison to the Significant Impact Level (SIL). The form of the standards, based on averages of ranked values across years, complicates this analysis…
Source · AERMOD User's Guide (EPA-454/B-26-001) §3.7.2.8, p. 3-180.
What it computes
The MAXDCONT option, applicable to 24-hour PM2.5, 1-hour NO2 and 1-hour SO2 standards, can be used to determine the contribution of each user-defined source group to the high ranked values for a target source group, paired in time and space. This is accomplished as an internal post-processing routine after the main model run is completed.
Source · §3.7.2.8, p. 3-180.
Three phrases in that passage carry the whole method:
"Paired in time and space." For each receptor, AERMOD identifies the exact hour that produced the ranked value for the target group — then reports what every other group was contributing at that same receptor, in that same hour. This is the crucial discipline. Adding up each group's own peak would be meaningless, because those peaks happen at different times under different winds; a neighbor's worst hour is usually a wind direction that carries nothing toward your receptor.
"For a target source group." You name a reference group — typically everything, the cumulative case. Its ranked values define the moments examined.
"An internal post-processing routine after the main model run." MAXDCONT runs inside the same execution, after concentrations are computed. It is not a second model run, but it is extra work, and (as below) it changes the run's memory profile.
How it is requested
Two forms. The first names an explicit range of ranks:
OU MAXDCONT GrpID UpperRank LowerRank FileName
The second names an upper rank and a concentration threshold, letting the model decide how far down to go:
OU MAXDCONT GrpID UpperRank THRESH ThreshValue FileName
Note the vocabulary, which reads backwards to most people the first time:
UpperRank and LowerRank are the upper bound and lower bound ranks (where upper bound rank implies higher concentrations and lower bound rank implies lower concentrations)
Source · §3.7.2.8, p. 3-180.
So the "upper" bound is the highest concentration — rank 1 — and the "lower" bound is a numerically larger rank further down the sorted list.
The threshold form is the one used in practice for a failing demonstration: set the threshold at the standard, and the model analyzes ranks downward until the target group's values fall below it:
The model will process each rank within the range specified but will stop after the first rank (in descending order of concentration) that is below the threshold.
Source · §3.7.2.8, p. 3-180.
In other words: analyze every modeled value that is at or above the standard, and stop when there is nothing left to explain.
The rules that bite
MAXDCONT can only analyze ranks you already asked the model to tabulate. This is the single most common way a MAXDCONT run fails, and the User's Guide flags it emphatically:
NOTE: It is important note that the range of ranks that can be analyzed under the MAXDCONT option is limited to the range of ranks (not the individual ranks) specified on the OU RECTABLE keyword, even when the THRESH option is used in lieu of specifying a LowerRank value.
Source · §3.7.2.8, p. 3-181. (The wording is the User's Guide's own.)
And the range must be wide enough — with hard minimums that produce a fatal error, and softer ones that produce a warning:
AERMOD will issue a fatal error if the THRESH option is used and the range of ranks is less than or equal to 8 for the 1-hr SO2 NAAQS, or less than or equal to 12 for the 1-hr NO2 and 24-hr PM2.5 NAAQS. Non-fatal warning messages will be generated if the THRESH option is used and the range of ranks is less than or equal to 24 for the 1-hr SO2 NAAQS, or less than or equal to 28 for the 1-hr NO2 and 24-hr PM2.5 NAAQS.
Source · §3.7.2.8, p. 3-181.
The practical reading: when you plan a contribution analysis, request a generous range of ranks in the ranked-value table — a range comfortably above those warning thresholds — rather than only the single rank that defines the design value. Ordering matters too: the ranked-table request must appear before the MAXDCONT request in the output pathway.
It cannot be combined with two other options. Because MAXDCONT holds hourly meteorology and time-varying inputs in memory to make the post-processing fast:
the MAXDCONT option cannot be used with the model "re-start" option using the INITFILE and SAVEFILE keywords (Section 3.2.15) on the CO pathway, or with the MULTYEAR option (Section 3.2.7) on the CO pathway.
Source · §3.7.2.8, p. 3-181.
The multi-year restriction has a real workflow consequence for fine particulate and the 1-hour standards: if you intend to run a contribution analysis, put the multiple years of meteorology in a single concatenated data file rather than using the multi-year option with separate runs. The User's Guide says so directly in the particulate section: "Multiple year analyses are best accomplished by including the multiple years of meteorology in a single data file" (§3.2.16.1, p. 3-59).
It costs memory. The same passage warns that storing every hour's meteorology, emissions, and background "may also significantly increase the memory storage requirements of the model." On a large run this is the option most likely to change the resources a run needs.
What you do with the answer
The output tells you, at each analyzed rank and receptor, how the cumulative value decomposes by group. That decomposition drives the next decision:
- The applicant's own contribution is small at the failing receptors. Then the failure is being carried by background and neighbors, and the argument moves toward the significant-impact comparison — is the project's own contribution below the Significant Impact Level at the times and places the standard is threatened? This is precisely the comparison the option was built to support.
- A single neighboring source dominates. Worth verifying that source is characterized correctly and — importantly — that it is not also embedded in the monitored background you added (see Nearby sources vs. the monitor). Double-counting a large neighbor is a common cause of a failure that is not real.
- The applicant's own sources dominate. Then the refinement work belongs at home: source characterization, operating assumptions, chemistry tiers, or ultimately controls and limits (see When the first run fails).
Each of those is a different project with a different cost, which is why the contribution analysis usually pays for itself the moment a cumulative run fails.
In PlumeSmart
Source-contribution analysis is available on runs whose pollutant and averaging period support it, with the ranked-value range requested wide enough to satisfy the model's requirements — and results are presented per receptor and per source group, so the share behind a failing design value is visible without hand-parsing the output file.