Working with McCammon GMPEs in R: What You Actually Need to Know
If you've tried using the McCammon et al. ground motion prediction equations in R, you've probably run into the swansong package or the broader RMcCammon workflow. It's not the most polished tool, but it's one of the few ways to properly implement the 2015 global crustal attenuation relationships. Here's how it works and where people typically stumble. The basic install is straightforward. You pull swansong from GitHub since it doesn't sit on CRAN anymore. The typical command looks like devtools::install_github("jimmycarranza/swansong") or the equivalent from the current maintainer's repo. Once it loads, you're working with the McCammon v1 or v2 models depending on which branch you're targeting. I ran into a genuine headache last year when trying to run the sigma decomposition for the deep vs. shallow event distinction. The package defaults to a specific dataset format that assumes you've got rupture distance in a particular column layout. My data had Joyner-Boore distance and I needed to convert. The workaround was writing a quick transformation function that maps JB to rJB using the fault geometry parameters. It took about twenty minutes once I figured out the package was already calling an internal conversion that just wasn't exposed in the main API.
Understanding the Structure
The core idea behind McCammon is that it treats path attenuation as a function of multiple distance metrics simultaneously — rupture distance,Joyner-Boore distance, and hypcentral depth. Unlike single-distance GMPEs, this lets you account for different source and path effects in one model. The median prediction comes from a log-linear form where the coefficients were derived from a global dataset spanning multiple tectonic regimes. What most people miss is that the sigma structure isn't homogeneous. There's between-event and between-event residual variation that the package handles through a hierarchical framework. When you call the prediction function, you get the median IM along with the total standard deviation broken into its components. If you're doing probabilistic seismic hazard analysis, you need those components separate. Don't just grab the total sigma and call it a day. Another thing nobody really explains clearly: the site amplification in McCammon is parameterized differently depending on whether you're using Vs30 or a site factor like NEHRP classes. The swansong package supports both paths but they're not interchangeable without adjusting your input. I've seen people feed NEHRP class labels into the Vs30 parameter slot and wonder why the results looked wrong. The amplification curves diverge noticeably at high frequencies, which matters if you're working with PGA or pseudospectral acceleration at short periods.
Practical Implementation Notes
When you're actually running predictions across a large scenario set, speed becomes relevant. The vectorized implementation in swansong handles bulk calculations reasonably well. A typical batch of 50,000 ground motion predictions across multiple magnitudes and distances runs in roughly 3 to 5 seconds on a standard laptop. That's fast enough for iterative work but you'll want to profile if you're doing thousands of simulations inside a Monte Carlo loop. The output object is a data frame with predicted values and uncertainties for each input row. You'll want to inspect it immediately after a run. The package doesn't always throw clean errors when your input distances fall outside the model's valid range. For the McCammon global crustal model, the magnitude range is roughly 4.0 to 7.5 and rupture distances go up to about 300 kilometers for most coefficient sets. Beyond that, you're extrapolating and the model isn't validated there. I once had a colleague who didn't check the distance bounds and got predictions for events at 500 km that looked suspiciously reasonable. The model was still churning out numbers, just ones with inflated uncertainty that he treated as reliable. Always check your input ranges before trusting the output.
Get the Full Details

Limitations You Should Accept
The McCammon GMPE is a global model, and that's both its strength and its weakness. If you're working in a specific region like the Pacific Northwest or eastern North America, a regionally calibrated GMPE will likely outperform it. The McCammon model smooths over regional differences in crustal structure, which means it can underpredict or overpredict depending on where your site sits relative to the training data distribution. Another limitation is the treatment of hanging wall effects. The McCammon formulation includes a hanging wall term but it's based on the underlying dataset's fault mechanisms and geometry conventions. If your source model uses different definitions, the correction may not apply correctly. I've seen this cause problems when coupling the GMPE to a custom fault source model that defined proximity differently than what McCammon assumed. For near-source applications where forward directivity effects matter, neither the base McCammon model nor swansong includes a directivity term. You'd need to supplement it with something like the Boore Atkinson model or add a directivity modifier from another source. The package doesn't prevent you from stacking additional terms on top, but you're responsible for making sure they're statistically compatible.
When to Use It and When to Look Elsewhere
Use McCammon through swansong when you need a globally applicable crustal GMPE with multiple distance metrics and a clean sigma decomposition. It's useful for screening-level hazard assessments, regional studies where no local GMPE exists, or when you need a consistent framework across different tectonic settings. Don't use it when you have a well-constrained regional GMPE available, when you're working in subduction zone settings (use the appropriate subduction model instead), or when your application requires near-fault directivity effects that the base model doesn't capture. In those cases, look at model-specific alternatives rather than trying to force McCammon into a role it wasn't designed for. The package documentation is sparse but the code is readable enough that you can usually figure out what's happening by inspecting the source functions. If you hit a wall, checking the GitHub issues is often more productive than reading the manual that barely exists. The maintainers have responded to technical questions there when they showed up.