diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/ServletUtil.java b/src/main/java/gov/usgs/earthquake/nshmp/www/ServletUtil.java
index 23f3917b59051fbab8711522e2a0a4213ffebd8d..18bd54070b8a59c1e14cef3f8d6420219adae510 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/ServletUtil.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/ServletUtil.java
@@ -28,10 +28,8 @@ import com.google.gson.JsonSerializer;
 
 import gov.usgs.earthquake.nshmp.calc.Site;
 import gov.usgs.earthquake.nshmp.calc.ValueFormat;
-import gov.usgs.earthquake.nshmp.geo.Location;
 import gov.usgs.earthquake.nshmp.gmm.Imt;
 import gov.usgs.earthquake.nshmp.model.HazardModel;
-import gov.usgs.earthquake.nshmp.model.SiteData;
 import gov.usgs.earthquake.nshmp.www.meta.MetaUtil;
 
 import io.micronaut.context.annotation.Value;
@@ -189,18 +187,6 @@ public class ServletUtil {
     return new Server(threads, timer);
   }
 
-  public static Site createSite(Location location, double vs30, SiteData siteData) {
-    Site.Builder builder = Site.builder()
-        .location(location)
-        .vs30(vs30);
-    SiteData.Values sdValues = siteData.get(location);
-    sdValues.z1p0.ifPresent(builder::z1p0);
-    sdValues.z2p5.ifPresent(builder::z2p5);
-    sdValues.zSed.ifPresent(builder::zSed);
-    builder.gmmTrees(sdValues.gmmTrees);
-    return builder.build();
-  }
-
   public static class Server {
 
     final int threads;
diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/DisaggService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/DisaggService.java
index 5f1d223fe315bc4409eda8e7b029f29d4d8b74cc..a0bdb002b8be81bd0a4f31bf275aea0b632de2a5 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/DisaggService.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/DisaggService.java
@@ -8,6 +8,7 @@ import static java.util.stream.Collectors.toList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.OptionalDouble;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.CompletableFuture;
@@ -27,6 +28,7 @@ import gov.usgs.earthquake.nshmp.calc.Disaggregation;
 import gov.usgs.earthquake.nshmp.calc.Hazard;
 import gov.usgs.earthquake.nshmp.calc.HazardCalcs;
 import gov.usgs.earthquake.nshmp.calc.Site;
+import gov.usgs.earthquake.nshmp.calc.Sites;
 import gov.usgs.earthquake.nshmp.geo.Location;
 import gov.usgs.earthquake.nshmp.gmm.Gmm;
 import gov.usgs.earthquake.nshmp.gmm.Imt;
@@ -147,7 +149,7 @@ public final class DisaggService {
         .build();
 
     Location loc = Location.create(request.longitude, request.latitude);
-    Site site = ServletUtil.createSite(loc, request.vs30, model.siteData());
+    Site site = Sites.locationToSite(loc, model.siteData(), OptionalDouble.of(request.vs30));
 
     // use HazardService.calcHazard() instead?
     CompletableFuture<Hazard> hazFuture = CompletableFuture.supplyAsync(
@@ -180,7 +182,7 @@ public final class DisaggService {
         .build();
 
     Location loc = Location.create(request.longitude, request.latitude);
-    Site site = ServletUtil.createSite(loc, request.vs30, model.siteData());
+    Site site = Sites.locationToSite(loc, model.siteData(), OptionalDouble.of(request.vs30));
 
     // could just get from HazardService
     CompletableFuture<Hazard> hazFuture = CompletableFuture.supplyAsync(
diff --git a/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/HazardService.java b/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/HazardService.java
index c6ba8adfb7472e9158da9734500444916b8a87ba..42830d66d40218da8e34f8686dbcc699787f5754 100644
--- a/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/HazardService.java
+++ b/src/main/java/gov/usgs/earthquake/nshmp/www/hazard/HazardService.java
@@ -12,6 +12,7 @@ import java.util.EnumMap;
 import java.util.EnumSet;
 import java.util.List;
 import java.util.Map;
+import java.util.OptionalDouble;
 import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -26,6 +27,7 @@ import gov.usgs.earthquake.nshmp.calc.DataType;
 import gov.usgs.earthquake.nshmp.calc.Hazard;
 import gov.usgs.earthquake.nshmp.calc.HazardCalcs;
 import gov.usgs.earthquake.nshmp.calc.Site;
+import gov.usgs.earthquake.nshmp.calc.Sites;
 import gov.usgs.earthquake.nshmp.data.MutableXySequence;
 import gov.usgs.earthquake.nshmp.data.XySequence;
 import gov.usgs.earthquake.nshmp.geo.Location;
@@ -114,7 +116,7 @@ public final class HazardService {
         .build();
 
     Location loc = Location.create(request.longitude, request.latitude);
-    Site site = ServletUtil.createSite(loc, request.vs30, model.siteData());
+    Site site = Sites.locationToSite(loc, model.siteData(), OptionalDouble.of(request.vs30));
 
     CompletableFuture<Hazard> future = CompletableFuture.supplyAsync(
         () -> HazardCalcs.hazard(
diff --git a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
index 89852afa2adca428b55a8c4d794d7ad655cd53c1..656649be1cb13202e679be92b7a3731e67f4a326 100644
--- a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
+++ b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
@@ -15,6 +15,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
+import java.util.OptionalDouble;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
@@ -35,8 +36,8 @@ import gov.usgs.earthquake.nshmp.calc.CalcConfig;
 import gov.usgs.earthquake.nshmp.calc.Hazard;
 import gov.usgs.earthquake.nshmp.calc.HazardCalcs;
 import gov.usgs.earthquake.nshmp.calc.Site;
+import gov.usgs.earthquake.nshmp.calc.Sites;
 import gov.usgs.earthquake.nshmp.data.XySequence;
-import gov.usgs.earthquake.nshmp.geo.Location;
 import gov.usgs.earthquake.nshmp.gmm.Imt;
 import gov.usgs.earthquake.nshmp.www.Application;
 import gov.usgs.earthquake.nshmp.www.hazard.HazardServiceUtils;
@@ -220,9 +221,10 @@ class NshmTestUtils {
       NshmModel nshmModel,
       NamedLocation location) {
 
-    Site site = createSite(
+    Site site = Sites.locationToSite(
         location.location(),
-        nshmModel.model.siteData());
+        nshmModel.model.siteData(),
+        OptionalDouble.empty());
 
     CalcConfig config = CalcConfig.copyOf(nshmModel.model.config())
         .imts(nshmModel.nshm.imts())
@@ -279,16 +281,6 @@ class NshmTestUtils {
     Files.write(resultPath, json.getBytes());
   }
 
-  private static Site createSite(Location loc, SiteData siteData) {
-    Site.Builder builder = Site.builder().location(loc);
-    SiteData.Values values = siteData.get(loc);
-    values.z1p0.ifPresent(builder::z1p0);
-    values.z2p5.ifPresent(builder::z2p5);
-    values.zSed.ifPresent(builder::zSed);
-    builder.gmmTrees(values.gmmTrees);
-    return builder.build();
-  }
-
   private static class Curve {
     double[] xs;
     double[] ys;