Skip to content
Snippets Groups Projects
Commit b699ba5e authored by Clayton, Brandon Scott's avatar Clayton, Brandon Scott
Browse files

Merge branch 'master' of code.usgs.gov:ghsc/nshmp/nshmp-netcdf

parents 30ed5e3c cd839c78
No related branches found
No related tags found
1 merge request!30Swagger
Showing
with 201 additions and 80 deletions
...@@ -18,6 +18,9 @@ import ucar.nc2.Group; ...@@ -18,6 +18,9 @@ import ucar.nc2.Group;
public class NetcdfUtils { public class NetcdfUtils {
// Tolerance for longitude/latitude comparisons
static final double LOCATION_TOLERANCE = 0.000001;
/** /**
* Creates a border going clockwise of the given longitudes and latitudes. * Creates a border going clockwise of the given longitudes and latitudes.
* *
...@@ -32,15 +35,16 @@ public class NetcdfUtils { ...@@ -32,15 +35,16 @@ public class NetcdfUtils {
builder.add(lat, longitudes[0]); builder.add(lat, longitudes[0]);
} }
for (var lon : longitudes) { // omit duplicate points at corners
builder.add(latitudes[latitudes.length - 1], lon); for (var i = 1; i < longitudes.length; i++) {
builder.add(latitudes[latitudes.length - 1], longitudes[i]);
} }
for (var i = latitudes.length - 1; i >= 0; i--) { for (var i = latitudes.length - 2; i >= 0; i--) {
builder.add(latitudes[i], longitudes[longitudes.length - 1]); builder.add(latitudes[i], longitudes[longitudes.length - 1]);
} }
for (var i = longitudes.length - 1; i >= 0; i--) { for (var i = longitudes.length - 2; i >= 0; i--) {
builder.add(latitudes[0], longitudes[i]); builder.add(latitudes[0], longitudes[i]);
} }
...@@ -94,7 +98,6 @@ public class NetcdfUtils { ...@@ -94,7 +98,6 @@ public class NetcdfUtils {
static int getIdxLTEQ(double[] a, double t) { static int getIdxLTEQ(double[] a, double t) {
// assumes array is in sorted order (a[i] < a[i+1]) // assumes array is in sorted order (a[i] < a[i+1])
// make sure target is within the range of the array // make sure target is within the range of the array
var tol = 0.000001;
var n = a.length; var n = a.length;
if (t < a[0] || t > a[n - 1]) { if (t < a[0] || t > a[n - 1]) {
...@@ -105,11 +108,11 @@ public class NetcdfUtils { ...@@ -105,11 +108,11 @@ public class NetcdfUtils {
} }
// if (t == a[0]) { // if (t == a[0]) {
if (DoubleMath.fuzzyEquals(a[0], t, tol)) { if (DoubleMath.fuzzyEquals(a[0], t, LOCATION_TOLERANCE)) {
return 0; return 0;
} }
// if (t == a[n - 1]) { // if (t == a[n - 1]) {
if (DoubleMath.fuzzyEquals(a[n - 1], t, tol)) { if (DoubleMath.fuzzyEquals(a[n - 1], t, LOCATION_TOLERANCE)) {
return n - 2; // return second to last index number return n - 2; // return second to last index number
} }
...@@ -129,12 +132,10 @@ public class NetcdfUtils { ...@@ -129,12 +132,10 @@ public class NetcdfUtils {
* Calculate fractional distance from a1 to t, between a1 and a2 * Calculate fractional distance from a1 to t, between a1 and a2
*/ */
static double calcFrac(double a1, double a2, double t) { static double calcFrac(double a1, double a2, double t) {
var tol = 0.00001; if (Math.abs(t - a1) < LOCATION_TOLERANCE) {
if (Math.abs(t - a1) < tol) {
// target value == a1 // target value == a1
return 0.0; return 0.0;
} else if (Math.abs(t - a2) < tol) { } else if (Math.abs(t - a2) < LOCATION_TOLERANCE) {
// target value == a2 // target value == a2
return 1.0; return 1.0;
} else { } else {
......
...@@ -3,7 +3,6 @@ package gov.usgs.earthquake.nshmp.netcdf.reader; ...@@ -3,7 +3,6 @@ package gov.usgs.earthquake.nshmp.netcdf.reader;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.Map;
import gov.usgs.earthquake.nshmp.data.XySequence; import gov.usgs.earthquake.nshmp.data.XySequence;
import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.gmm.Imt;
...@@ -20,9 +19,10 @@ public class StaticHazard extends EnumMap<Imt, XySequence> { ...@@ -20,9 +19,10 @@ public class StaticHazard extends EnumMap<Imt, XySequence> {
putAll(staticHazard); putAll(staticHazard);
} }
public Map<Imt, XySequence> staticHazard() { // unnecessary method?
return Map.copyOf(this); // public Map<Imt, XySequence> staticHazard() {
} // return Map.copyOf(this);
// }
public static Builder builder() { public static Builder builder() {
return new Builder(); return new Builder();
......
package gov.usgs.earthquake.nshmp.netcdf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class NshmGroupTests {
@Test
final void testCONUS_2018() {
assertEquals(NshmGroup.CONUS_2018.toString(), "2018 Conterminous U.S. NSHM");
assertEquals(NshmGroup.CONUS_2018.baseGroup(), "/CONUS/2018/v1.1");
assertEquals(NshmGroup.CONUS_2018.locationPrecision(), 2);
}
}
...@@ -20,17 +20,14 @@ import org.junit.jupiter.params.provider.MethodSource; ...@@ -20,17 +20,14 @@ import org.junit.jupiter.params.provider.MethodSource;
import com.google.common.io.Resources; import com.google.common.io.Resources;
import gov.usgs.earthquake.nshmp.data.XySequence; import gov.usgs.earthquake.nshmp.data.XySequence;
import gov.usgs.earthquake.nshmp.geo.BorderType;
import gov.usgs.earthquake.nshmp.geo.Location; import gov.usgs.earthquake.nshmp.geo.Location;
import gov.usgs.earthquake.nshmp.geo.LocationList; import gov.usgs.earthquake.nshmp.geo.LocationList;
import gov.usgs.earthquake.nshmp.geo.Regions;
import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.gmm.Imt;
import gov.usgs.earthquake.nshmp.netcdf.reader.BoundingHazards; import gov.usgs.earthquake.nshmp.netcdf.reader.BoundingHazards;
import gov.usgs.earthquake.nshmp.netcdf.reader.NetcdfUtils;
import gov.usgs.earthquake.nshmp.netcdf.reader.StaticHazard; import gov.usgs.earthquake.nshmp.netcdf.reader.StaticHazard;
import gov.usgs.earthquake.nshmp.netcdf.reader.StaticHazards; import gov.usgs.earthquake.nshmp.netcdf.reader.StaticHazards;
class NshmNetcdfReaderTests { public class NshmNetcdfReaderTests {
static final String CONUS_TEST_FILE = "conus-test.nc"; static final String CONUS_TEST_FILE = "conus-test.nc";
static final Path NETCDF_PATH = Paths.get(Resources.getResource(CONUS_TEST_FILE).getPath()); static final Path NETCDF_PATH = Paths.get(Resources.getResource(CONUS_TEST_FILE).getPath());
...@@ -41,13 +38,14 @@ class NshmNetcdfReaderTests { ...@@ -41,13 +38,14 @@ class NshmNetcdfReaderTests {
// difference tolerance, until we can incorporate precision into // difference tolerance, until we can incorporate precision into
// NshmNetcdfReader // NshmNetcdfReader
static final double IML_TOL = 1e-6; public static final double IML_TOL = 1e-6;
static final double HAZ_TOL = 1e-8; static final double HAZ_TOL = 1e-8;
static final Location TARGET_LOCATION = Location.create(39.213, -105.234); static final Location TARGET_LOCATION = Location.create(39.213, -105.234);
static final double[] EXPECTED_LONGITUDES = new double[] { -105.3, -105.25, -105.2, -105.15 }; public static final double[] EXPECTED_LONGITUDES =
static final double[] EXPECTED_LATITUDES = new double[] { 39.15, 39.2, 39.25, 39.3 }; new double[] { -105.3, -105.25, -105.2, -105.15 };
public static final double[] EXPECTED_LATITUDES = new double[] { 39.15, 39.2, 39.25, 39.3 };
static final LocationList BOUNDING_LOCATIONS = LocationList.builder() static final LocationList BOUNDING_LOCATIONS = LocationList.builder()
.add(EXPECTED_LATITUDES[1], EXPECTED_LONGITUDES[1]) .add(EXPECTED_LATITUDES[1], EXPECTED_LONGITUDES[1])
...@@ -87,8 +85,8 @@ class NshmNetcdfReaderTests { ...@@ -87,8 +85,8 @@ class NshmNetcdfReaderTests {
new double[] { 4.1153710E-02, 3.8681961E-03, 1.2028426E-04, 3.5812084E-07 }, new double[] { 4.1153710E-02, 3.8681961E-03, 1.2028426E-04, 3.5812084E-07 },
new double[] { 5.2503492E-02, 3.4418438E-03, 4.0267402E-05, 4.5693341E-08 }); new double[] { 5.2503492E-02, 3.4418438E-03, 4.0267402E-05, 4.5693341E-08 });
static final List<SiteClass> SITE_CLASSES = List.of(SiteClass.CD, SiteClass.C); public static final List<SiteClass> SITE_CLASSES = List.of(SiteClass.CD, SiteClass.C);
static final List<Imt> IMTS = List.of(Imt.PGA, Imt.SA0P4); public static final List<Imt> IMTS = List.of(Imt.PGA, Imt.SA0P4);
static final int TARGET_LOWER_LEFT_LONGITUDE_IDX = 1; static final int TARGET_LOWER_LEFT_LONGITUDE_IDX = 1;
static final int TARGET_LOWER_LEFT_LATITUDE_IDX = 1; static final int TARGET_LOWER_LEFT_LATITUDE_IDX = 1;
...@@ -96,11 +94,12 @@ class NshmNetcdfReaderTests { ...@@ -96,11 +94,12 @@ class NshmNetcdfReaderTests {
static final double TARGET_LONGITUDE_FRAC; static final double TARGET_LONGITUDE_FRAC;
static final double TARGET_LATITUDE_FRAC; static final double TARGET_LATITUDE_FRAC;
static Map<SiteClass, Map<Imt, double[]>> IMLS = new HashMap<>(); public static Map<SiteClass, Map<Imt, double[]>> IMLS = new HashMap<>();
static BoundingHazards BOUNDING_HAZARDS; static BoundingHazards BOUNDING_HAZARDS;
static final NshmNetcdfReader NETCDF = new NshmNetcdfReader(NshmGroup.CONUS_2018, NETCDF_PATH); public static final NshmNetcdfReader NETCDF =
new NshmNetcdfReader(NshmGroup.CONUS_2018, NETCDF_PATH);
static { static {
var builder = BoundingHazards.builder(); var builder = BoundingHazards.builder();
...@@ -154,57 +153,6 @@ class NshmNetcdfReaderTests { ...@@ -154,57 +153,6 @@ class NshmNetcdfReaderTests {
assertTrue(NshmGroup.CONUS_2018.equals(NETCDF.nshmGroup())); assertTrue(NshmGroup.CONUS_2018.equals(NETCDF.nshmGroup()));
} }
@Test
final void coordinatesTests() {
var coords = NETCDF.coordinates();
// Check locations
assertArrayEquals(EXPECTED_LATITUDES, coords.latitudes());
assertArrayEquals(EXPECTED_LONGITUDES, coords.longitudes());
// Check IMTs
assertEquals(IMTS, coords.imts());
assertEquals(IMTS.size(), coords.imts().size());
// Check site classes
assertEquals(SITE_CLASSES, coords.siteClasses());
// Check region
var border = NetcdfUtils.buildBorder(EXPECTED_LONGITUDES, EXPECTED_LATITUDES);
var expectedRegion = Regions.create("test-region", border, BorderType.MERCATOR_LINEAR);
var expectedBorder = expectedRegion.border();
var actualRegion = coords.region();
var actualBorder = actualRegion.border();
assertEquals(expectedBorder.size(), actualBorder.size());
assertEquals(expectedBorder.bounds().max, expectedBorder.bounds().max);
assertEquals(expectedBorder.bounds().min, expectedBorder.bounds().min);
for (var i = 0; i < expectedBorder.size(); i++) {
assertEquals(expectedBorder.get(i), actualBorder.get(i));
}
// Check IMLs
var actualImls = coords.imls();
assertEquals(IMLS.size(), actualImls.size());
for (var imlEntry : IMLS.entrySet()) {
var siteClass = imlEntry.getKey();
assertTrue(actualImls.containsKey(siteClass));
assertEquals(imlEntry.getValue().size(), actualImls.get(siteClass).size());
for (var siteEntry : imlEntry.getValue().entrySet()) {
var imt = siteEntry.getKey();
var expectedValue = siteEntry.getValue();
var actualValue = actualImls.get(siteClass).get(imt);
assertTrue(actualImls.get(siteClass).containsKey(imt));
assertArrayEquals(expectedValue, actualValue, IML_TOL);
}
}
}
@Test @Test
final void pathTests() { final void pathTests() {
assertEquals(NETCDF_PATH, NETCDF.path()); assertEquals(NETCDF_PATH, NETCDF.path());
......
package gov.usgs.earthquake.nshmp.netcdf.reader;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
class BoundingHazardsTests {
@Test
final void builderTest() {
// calling build() on empty builder should fail
assertThrows(IllegalStateException.class, () -> {
var boundingHazards = BoundingHazards.builder().build();
});
}
}
package gov.usgs.earthquake.nshmp.netcdf.reader;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import gov.usgs.earthquake.nshmp.geo.BorderType;
import gov.usgs.earthquake.nshmp.geo.Regions;
import gov.usgs.earthquake.nshmp.netcdf.NshmNetcdfReaderTests;
class NetcdfCoordinatesTest {
@Test
final void coordinatesTests() {
var coords = NshmNetcdfReaderTests.NETCDF.coordinates();
// Check locations
assertArrayEquals(NshmNetcdfReaderTests.EXPECTED_LATITUDES, coords.latitudes());
assertArrayEquals(NshmNetcdfReaderTests.EXPECTED_LONGITUDES, coords.longitudes());
// Check IMTs
assertEquals(NshmNetcdfReaderTests.IMTS, coords.imts());
assertEquals(NshmNetcdfReaderTests.IMTS.size(), coords.imts().size());
// Check site classes
assertEquals(NshmNetcdfReaderTests.SITE_CLASSES, coords.siteClasses());
// Check region
var border = NetcdfUtils.buildBorder(
NshmNetcdfReaderTests.EXPECTED_LONGITUDES,
NshmNetcdfReaderTests.EXPECTED_LATITUDES);
var expectedRegion = Regions.create("test-region", border, BorderType.MERCATOR_LINEAR);
var expectedBorder = expectedRegion.border();
var actualRegion = coords.region();
var actualBorder = actualRegion.border();
assertEquals(expectedBorder.size(), actualBorder.size());
assertEquals(expectedBorder.bounds().max, actualBorder.bounds().max);
assertEquals(expectedBorder.bounds().min, actualBorder.bounds().min);
for (var i = 0; i < expectedBorder.size(); i++) {
assertEquals(expectedBorder.get(i), actualBorder.get(i));
}
// Check IMLs
var actualImls = coords.imls();
assertEquals(NshmNetcdfReaderTests.IMLS.size(), actualImls.size());
for (var imlEntry : NshmNetcdfReaderTests.IMLS.entrySet()) {
var siteClass = imlEntry.getKey();
assertTrue(actualImls.containsKey(siteClass));
assertEquals(imlEntry.getValue().size(), actualImls.get(siteClass).size());
for (var siteEntry : imlEntry.getValue().entrySet()) {
var imt = siteEntry.getKey();
var expectedValue = siteEntry.getValue();
var actualValue = actualImls.get(siteClass).get(imt);
assertTrue(actualImls.get(siteClass).containsKey(imt));
assertArrayEquals(expectedValue, actualValue, NshmNetcdfReaderTests.IML_TOL);
}
}
}
}
...@@ -11,6 +11,7 @@ import java.util.List; ...@@ -11,6 +11,7 @@ import java.util.List;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import gov.usgs.earthquake.nshmp.data.XySequence; import gov.usgs.earthquake.nshmp.data.XySequence;
import gov.usgs.earthquake.nshmp.geo.LocationList;
import gov.usgs.earthquake.nshmp.gmm.Imt; import gov.usgs.earthquake.nshmp.gmm.Imt;
import gov.usgs.earthquake.nshmp.netcdf.SiteClass; import gov.usgs.earthquake.nshmp.netcdf.SiteClass;
...@@ -25,6 +26,10 @@ class NetcdfUtilsTests { ...@@ -25,6 +26,10 @@ class NetcdfUtilsTests {
39.13, 39.14, 39.15, 39.16, 39.17, 39.18, 39.19, 39.20, 39.21, 39.22, 39.23, 39.24, 39.25, 39.13, 39.14, 39.15, 39.16, 39.17, 39.18, 39.19, 39.20, 39.21, 39.22, 39.23, 39.24, 39.25,
39.26, 39.27, 39.28, 39.29, 39.30, 39.31, 39.32, 39.33, 39.34, 39.35 }; 39.26, 39.27, 39.28, 39.29, 39.30, 39.31, 39.32, 39.33, 39.34, 39.35 };
private static final double[] BORDER_LONGITUDES = new double[] { 5.0, 6.0 };
private static final double[] BORDER_LATITUDES = new double[] { 8.0, 9.0 };
private static final LocationList BORDER_LOCATIONS;
private static final double TOL = 1e-7; private static final double TOL = 1e-7;
static StaticHazards mapHaz0; static StaticHazards mapHaz0;
...@@ -38,6 +43,15 @@ class NetcdfUtilsTests { ...@@ -38,6 +43,15 @@ class NetcdfUtilsTests {
private static final double FRAC = 0.5; private static final double FRAC = 0.5;
static { static {
BORDER_LOCATIONS = LocationList.builder()
.add(BORDER_LATITUDES[0], BORDER_LONGITUDES[0])
.add(BORDER_LATITUDES[1], BORDER_LONGITUDES[0])
.add(BORDER_LATITUDES[1], BORDER_LONGITUDES[1])
.add(BORDER_LATITUDES[0], BORDER_LONGITUDES[1])
.add(BORDER_LATITUDES[0], BORDER_LONGITUDES[0])
.build();
var siteClasses = List.of(SiteClass.B, SiteClass.C, SiteClass.D); var siteClasses = List.of(SiteClass.B, SiteClass.C, SiteClass.D);
var imts = List.of(Imt.PGA, Imt.SA0P1, Imt.SA1P5); var imts = List.of(Imt.PGA, Imt.SA0P1, Imt.SA1P5);
var imlValues = new double[] { 0.1, 0.5, 0.75 }; var imlValues = new double[] { 0.1, 0.5, 0.75 };
...@@ -106,7 +120,12 @@ class NetcdfUtilsTests { ...@@ -106,7 +120,12 @@ class NetcdfUtilsTests {
} }
@Test @Test
final void testGetIdxLTEQ() { final void buildBorderTest() {
assertEquals(BORDER_LOCATIONS, NetcdfUtils.buildBorder(BORDER_LONGITUDES, BORDER_LATITUDES));
}
@Test
final void getIdxLTEQTest() {
// target is out of range, expect IAE // target is out of range, expect IAE
assertThrows(IllegalArgumentException.class, () -> { assertThrows(IllegalArgumentException.class, () -> {
NetcdfUtils.getIdxLTEQ(LONGITUDES, -100.0); NetcdfUtils.getIdxLTEQ(LONGITUDES, -100.0);
...@@ -134,7 +153,25 @@ class NetcdfUtilsTests { ...@@ -134,7 +153,25 @@ class NetcdfUtilsTests {
} }
@Test @Test
final void testCalcGridFrac() { final void calcFracTest() {
double bottom = 5.0;
double top = bottom + 1.0;
double frac = 0.36;
assertEquals(0.0, NetcdfUtils.calcFrac(bottom, top, bottom));
assertEquals(1.0, NetcdfUtils.calcFrac(bottom, top, top));
assertEquals(0.0, NetcdfUtils.calcFrac(
bottom,
top,
bottom + NetcdfUtils.LOCATION_TOLERANCE * 0.9));
assertEquals(1.0, NetcdfUtils.calcFrac(
bottom,
top,
top - NetcdfUtils.LOCATION_TOLERANCE * 0.9));
assertEquals(frac, NetcdfUtils.calcFrac(bottom, top, bottom + frac), 1e-4);
}
@Test
final void calcGridFracTest() {
double f = 0.13; double f = 0.13;
int i = 4; int i = 4;
assertEquals(f, assertEquals(f,
...@@ -147,7 +184,7 @@ class NetcdfUtilsTests { ...@@ -147,7 +184,7 @@ class NetcdfUtilsTests {
} }
@Test @Test
final void testLinearInterpolate() { final void linearInterpolateTest() {
var actual = NetcdfUtils.linearInterpolate(mapHaz0, mapHaz1, FRAC); var actual = NetcdfUtils.linearInterpolate(mapHaz0, mapHaz1, FRAC);
assertTrue(mapHazTarget.keySet().containsAll(actual.keySet())); assertTrue(mapHazTarget.keySet().containsAll(actual.keySet()));
......
package gov.usgs.earthquake.nshmp.netcdf.reader;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
class StaticHazardTests {
@Test
final void builderTest() {
// calling build() on empty builder should fail
assertThrows(IllegalStateException.class, () -> {
var staticHazard = StaticHazard.builder().build();
});
}
}
package gov.usgs.earthquake.nshmp.netcdf.reader;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
class StaticHazardsTests {
@Test
final void builderTest() {
// calling build() on empty builder should fail
assertThrows(IllegalStateException.class, () -> {
var staticHazards = StaticHazards.builder().build();
});
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment