diff --git a/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java b/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java
index 33a78723cacc1a930504186d6f3bd0033ae84ae5..7b08a39c5605e1b8d8f2f5313d86a686f33c3854 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/data/Sequences.java
@@ -6,7 +6,9 @@ import static gov.usgs.earthquake.nshmp.data.DoubleData.areMonotonic;
 
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.TreeMap;
 import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * Static methods we don't want in public interfaces.
@@ -65,8 +67,7 @@ class Sequences {
     if (xySequences.size() == 1) {
       return true;
     }
-    // Safe covariant cast
-    ArrayXySequence firstXy = (ArrayXySequence) xySequences.iterator().next();
+    ArrayXySequence firstXy = getFirstSequence(xySequences);
     Predicate<XySequence> firstXsPredicate = other -> {
       return Arrays.equals(
           firstXy.xs,
@@ -77,4 +78,43 @@ class Sequences {
         .allMatch(firstXsPredicate);
   }
 
+  /**
+   * Combine {@code Collection} of {@code XySequence} such that the resulting
+   * x-values are the union of all specified sequences, and the y-values are
+   * summed accordingly.
+   * 
+   * @param xySequences
+   * @return xys
+   */
+  static XySequence combine(Collection<XySequence> xySequences) {
+    checkState(!xySequences.isEmpty());
+    if (xySequences.size() == 1) {
+      return getFirstSequence(xySequences);
+    }
+    if (areSimilar(xySequences)) {
+      MutableXySequence result = MutableXySequence.emptyCopyOf(getFirstSequence(xySequences));
+      for (XySequence xys : xySequences) {
+        result.add(xys);
+      }
+      return result;
+    }
+
+    var combinedMap = xySequences.stream()
+        .flatMap(XySequence::stream)
+        .collect(Collectors.toMap(
+            (XyPoint xy) -> (double) xy.x(),
+            (XyPoint xy) -> (double) xy.y(),
+            (a, b) -> a + b,
+            TreeMap::new));
+    return XySequence.create(
+        combinedMap.keySet(),
+        combinedMap.values());
+  }
+
+  private static ArrayXySequence getFirstSequence(Collection<XySequence> xySequences) {
+    checkState(!xySequences.isEmpty());
+    // Safe covariant cast
+    return (ArrayXySequence) xySequences.iterator().next();
+  }
+
 }
diff --git a/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java b/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java
index 53be21dafd087505aaef8d3961699f6be4201fb3..302918a71a4bdf03bc35e5a8789cc59c1945ff0a 100644
--- a/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java
+++ b/src/test/java/gov/usgs/earthquake/nshmp/data/SequencesTests.java
@@ -1,9 +1,11 @@
 package gov.usgs.earthquake.nshmp.data;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import java.util.Arrays;
 import java.util.List;
 
 import org.junit.jupiter.api.Test;
@@ -12,59 +14,108 @@ import com.google.common.collect.ImmutableList;
 
 class SequencesTests {
 
-  private static double[] xs1 = new double[] { 0, 1, 2, 3 };
-  private static double[] xs2 = new double[] { 1, 2, 3, 4 };
-  private static double[] xs3 = new double[] { 6, 7, 8 };
-
-  private static double[] ys1 = new double[] { 10, 9, 8, 7 };
-  private static double[] ys2 = new double[] { 5, 4, 3, 2 };
-  private static double[] ys3 = new double[] { 10, 9, 8 };
-
-  private static XySequence xyBase = XySequence.create(xs1, ys1);
-  private static XySequence xySameXs = XySequence.create(xs1, ys2);
-  private static XySequence xyDifferentXs = XySequence.create(xs2, ys2);
-  private static XySequence xyShorter = XySequence.create(xs3, ys3);
-
-  private static List<XySequence> emptyCollection = new ImmutableList.Builder<XySequence>().build();
-  private static List<XySequence> singleSequences =
-      new ImmutableList.Builder<XySequence>()
-          .add(xyBase)
-          .build();
-  private static List<XySequence> identicalSequences =
-      new ImmutableList.Builder<XySequence>()
-          .add(xyBase)
-          .add(xyBase)
-          .build();
-  private static List<XySequence> sameXs =
-      new ImmutableList.Builder<XySequence>()
-          .add(xyBase)
-          .add(xySameXs)
-          .build();
-  private static List<XySequence> differentXs =
-      new ImmutableList.Builder<XySequence>()
-          .add(xyBase)
-          .add(xySameXs)
-          .add(xyDifferentXs)
-          .build();
-  private static List<XySequence> withShorterXs =
-      new ImmutableList.Builder<XySequence>()
-          .add(xyBase)
-          .add(xySameXs)
-          .add(xyDifferentXs)
-          .add(xyShorter)
-          .build();
+  private static final double[] xs1 = new double[] { 0, 1, 2, 3 };
+  private static final double[] xs2 = new double[] { 1, 2, 3, 4 };
+  private static final double[] xs3 = new double[] { 5, 6, 7 };
 
-  @Test
-  final void areSimilarTests() {
+  private static final double[] ys1 = new double[] { 10, 9, 8, 7 };
+  private static final double[] ys2 = new double[] { 5, 4, 3, 2 };
+  private static final double[] ys3 = new double[] { 10, 9, 8 };
+
+  private static final XySequence xyBase = XySequence.create(xs1, ys1);
+  private static final XySequence xySameXs = XySequence.create(xs1, ys2);
+  private static final XySequence xyDifferentXs = XySequence.create(xs2, ys2);
+  private static final XySequence xyShorter = XySequence.create(xs3, ys3);
+
+  private static final List<XySequence> emptyCollection;
+  private static final List<XySequence> singleSequence;
+  private static final XySequence expectedSingleSequenceResults;
+  private static final List<XySequence> identicalSequences;
+  private static final XySequence expectedIdenticalSequences;
+  private static final List<XySequence> sameXs;
+  private static final XySequence expectedSameXs;
+  private static final List<XySequence> differentXs;
+  private static final XySequence expectedDifferentXs;
+  private static final List<XySequence> withShorterXs;
+  private static final XySequence expectedWithShorterXs;
+
+  static {
+    emptyCollection = new ImmutableList.Builder<XySequence>().build();
+
+    singleSequence = new ImmutableList.Builder<XySequence>()
+        .add(xyBase)
+        .build();
+    expectedSingleSequenceResults = xyBase;
+
+    identicalSequences = new ImmutableList.Builder<XySequence>()
+        .add(xyBase)
+        .add(xyBase)
+        .build();
+    double[] result = new double[xs1.length];
+    Arrays.setAll(result, i -> ys1[i] + ys1[i]);
+    expectedIdenticalSequences = XySequence.create(xs1, result);
 
+    sameXs = new ImmutableList.Builder<XySequence>()
+        .add(xyBase)
+        .add(xySameXs)
+        .build();
+    Arrays.setAll(result, i -> ys1[i] + ys2[i]);
+    expectedSameXs = XySequence.create(xs1, result);
+
+    differentXs = new ImmutableList.Builder<XySequence>()
+        .add(xyBase)
+        .add(xyDifferentXs)
+        .build();
+    // manually construct for now
+    expectedDifferentXs = XySequence.create(
+        new double[] { 0, 1, 2, 3, 4 },
+        new double[] { 10, 14, 12, 10, 2 });
+
+    withShorterXs = new ImmutableList.Builder<XySequence>()
+        .add(xyBase)
+        .add(xyDifferentXs)
+        .add(xyShorter)
+        .build();
+    // manually construct for now
+    expectedWithShorterXs = XySequence.create(
+        new double[] { 0, 1, 2, 3, 4, 5, 6, 7 },
+        new double[] { 10, 14, 12, 10, 2, 10, 9, 8 });
+  }
+
+  @Test
+  final void areSimilarTests_emptyThrowsISE() {
     assertThrows(IllegalStateException.class, () -> {
       Sequences.areSimilar(emptyCollection);
     });
-    assertTrue(Sequences.areSimilar(singleSequences));
+  }
+
+  @Test
+  final void areSimilarTests() {
+    assertTrue(Sequences.areSimilar(singleSequence));
     assertTrue(Sequences.areSimilar(identicalSequences));
     assertTrue(Sequences.areSimilar(sameXs));
     assertFalse(Sequences.areSimilar(differentXs));
     assertFalse(Sequences.areSimilar(withShorterXs));
   }
 
+  @Test
+  final void combineTests_emptyThrowsISE() {
+    assertThrows(IllegalStateException.class, () -> {
+      Sequences.combine(emptyCollection);
+    });
+  }
+
+  @Test
+  final void combineTests_similarSequences() {
+    assertEquals(expectedSingleSequenceResults, Sequences.combine(singleSequence));
+    assertEquals(expectedIdenticalSequences, Sequences.combine(identicalSequences));
+    assertEquals(expectedSameXs, Sequences.combine(sameXs));
+  }
+
+  @Test
+  final void combineTests_dissimilarSequences() {
+    assertEquals(expectedDifferentXs, Sequences.combine(differentXs));
+    assertEquals(expectedWithShorterXs, Sequences.combine(withShorterXs));
+  }
+
 }