def test_cca06_add_1d_model(self): """ Tests that we can add a 1D background model to CCA06 using tiling. This is a generic verification just to ensure that tiling works on the user's computer as we expect them to use it with this model. Returns: None """ self._test_start("CCA06 tiling with 1D model works") sd_test = [ SeismicData(Point(-120.65, 35.64, 0)), SeismicData(Point(-125, 40, 0)) ] self.assertTrue(UCVM.query(sd_test, "cca06;1d[SCEC]", ["velocity"])) self.assertAlmostEqual(sd_test[0].velocity_properties.vp, 5076.7466, 4) self.assertAlmostEqual(sd_test[0].velocity_properties.vs, 2838.2566, 4) self.assertAlmostEqual(sd_test[0].velocity_properties.density, 2493.9988, 4) self.assertEqual(sd_test[0].velocity_properties.vp_source, "cca06") self.assertAlmostEqual(sd_test[1].velocity_properties.vp, 5000, 4) self.assertAlmostEqual(sd_test[1].velocity_properties.vs, 2886.7513, 4) self.assertAlmostEqual(sd_test[1].velocity_properties.density, 2654.5000, 4) self.assertEqual(sd_test[1].velocity_properties.vp_source, "scec 1d (interpolated)") self._test_end()
def test_fails_incorrect_lat_lon_bounds(self): """ Tests that the USGS/NOAA map does not return heights for latitudes and longitudes that fall outside of the possible ranges. Returns: None """ self._test_start("test for out-of-bounds lat, lon") sd_test = [ SeismicData(Point(200, 34, 0)), SeismicData(Point(-118, 340, 0)) ] self.assertTrue(UCVM.query(sd_test, "usgs-noaa", ["elevation"])) self.assertEqual(sd_test[0].elevation_properties.elevation, None) self.assertEqual(sd_test[0].elevation_properties.elevation_source, None) self.assertEqual(sd_test[1].elevation_properties.elevation, None) self.assertEqual(sd_test[1].elevation_properties.elevation_source, None) self._test_end()
def test_cvms4_basic_depth(self): """ Tests UCVM's basic query capabilities with CVM-S4 using depth. This tests that a known point within the model returns the correct material properties and also that a known point outside of the model returns the SCEC 1D background material properties. Returns: None """ self._test_start("test for UCVM query by depth") sd_test = [SeismicData(Point(-118, 34, 0))] self.assertTrue(UCVM.query(sd_test, "cvms4", ["velocity"])) assert_velocity_properties( self, sd_test[0], VelocityProperties(696.491, 213, 1974.976, None, None, "cvms4", "cvms4", "cvms4", None, None)) sd_test = [SeismicData(Point(-130, 40, 0))] self.assertTrue(UCVM.query(sd_test, "cvms4", ["velocity"])) assert_velocity_properties( self, sd_test[0], VelocityProperties(5000, 2886.751, 2654.5, None, None, "cvms4", "cvms4", "cvms4", None, None)) self._test_end()
def test_etopo1_basic(self): """ Tests that the USGS/NOAA map delivers the expected ETOPO1 data at certain latitudes and longitudes around the world. Returns: None """ self._test_start("test for correct ETOPO1 data") sd_test = [ SeismicData(Point(-122.65, 49.21667, 0)), SeismicData(Point(-114.0833, 51.05, 0)) ] self.assertTrue(UCVM.query(sd_test, "usgs-noaa", ["elevation"])) self.assertAlmostEqual(sd_test[0].elevation_properties.elevation, 19.994, 3) self.assertEqual(sd_test[0].elevation_properties.elevation_source, "usgs-noaa") self.assertAlmostEqual(sd_test[1].elevation_properties.elevation, 1051.015, 3) self.assertEqual(sd_test[1].elevation_properties.elevation_source, "usgs-noaa") self._test_end()
def test_cvmh_query_gtl(self): """ Tests the CVM-H query capabilities both with the GTL and without. Returns: None """ self._test_start("test for CVM-H query using GTL") sd_test = [SeismicData(Point(-118, 34, 0))] self.assertTrue(UCVM.query(sd_test, "cvmh1510[gtl]")) assert_velocity_properties( self, sd_test[0], VelocityProperties(824.177, 195, 1084.062, None, None, "cvmh1510", "cvmh1510", "cvmh1510", None, None)) sd_test = [SeismicData(Point(-118, 34, 0))] self.assertTrue(UCVM.query(sd_test, "cvmh1510")) # No 1D means None for everything. assert_velocity_properties( self, sd_test[0], VelocityProperties(2484.3879, 969.2999, 2088.316, None, None, "cvmh1510", "cvmh1510", "cvmh1510", None, None)) self._test_end()
def test_nationalmap_basic(self): """ Tests that the USGS/NOAA map delivers the expected National Map data at certain latitudes and longitudes around the world. Returns: None """ self._test_start("test for correct National Map data") sd_test = [ SeismicData(Point(-118, 34, 0)), SeismicData(Point(-119, 35, 0)) ] self.assertTrue(UCVM.query(sd_test, "usgs-noaa", ["elevation"])) self.assertAlmostEqual(sd_test[0].elevation_properties.elevation, 287.997, 3) self.assertEqual(sd_test[0].elevation_properties.elevation_source, "usgs-noaa") self.assertAlmostEqual(sd_test[1].elevation_properties.elevation, 466.993, 3) self.assertEqual(sd_test[1].elevation_properties.elevation_source, "usgs-noaa") self._test_end()
def test_cvmh_query_1d_background(self): """ Tests the CVM-H query capabilities both with the 1D background model and without. Returns: None """ self._test_start("test for CVM-H query with 1D model") sd_test = [SeismicData(Point(-122.0322, 37.3230, 0))] self.assertTrue(UCVM.query(sd_test, "cvmh1510[1d]")) assert_velocity_properties( self, sd_test[0], VelocityProperties(5000.0, 2886.7514, 2654.5, None, None, "cvmh1510", "cvmh1510", "cvmh1510", None, None)) sd_test = [SeismicData(Point(-122.0322, 37.3230, 0))] self.assertTrue(UCVM.query(sd_test, "cvmh1510")) # No 1D means None for everything. assert_velocity_properties( self, sd_test[0], VelocityProperties(None, None, None, None, None, None, None, None, None, None)) self._test_end()
def test_cvms426_add_1d_model(self): """ Tests that we can add a 1D background model to CVM-S4.26 using tiling. This is a generic verification just to ensure that tiling works on the user's computer as we expect them to use it with this model. Returns: None """ self._test_start("CVM-S4.26 tiling with 1D model works") sd_test = [ SeismicData(Point(-118, 34, 0)), SeismicData(Point(-125, 40, 0)) ] self.assertTrue(UCVM.query(sd_test, "cvms426;1d[SCEC]", ["velocity"])) self.assertAlmostEqual(sd_test[0].velocity_properties.vp, 1860.9648, 4) self.assertAlmostEqual(sd_test[0].velocity_properties.vs, 909.3662, 4) self.assertAlmostEqual(sd_test[0].velocity_properties.density, 2050.1179, 4) self.assertEqual(sd_test[0].velocity_properties.vp_source, "cvms426") self.assertAlmostEqual(sd_test[1].velocity_properties.vp, 5000, 4) self.assertAlmostEqual(sd_test[1].velocity_properties.vs, 2886.7513, 4) self.assertAlmostEqual(sd_test[1].velocity_properties.density, 2654.5000, 4) self.assertEqual(sd_test[1].velocity_properties.vp_source, "scec 1d (interpolated)") self._test_end()
def test_cvms4_basic_elevation(self): """ Tests UCVM's query capabilities with CVM-S4 but using elevation. The tests are the same as with test_cvms4_basic_depth. Returns: None """ self._test_start("test for UCVM query by elevation") sd_test = [SeismicData(Point(-118, 34, 0, UCVM_ELEVATION))] self.assertTrue( UCVM.query(sd_test, "cvms4.usgs-noaa.elevation", ["velocity", "elevation"])) assert_velocity_properties( self, sd_test[0], VelocityProperties(2677.1596, 725.390, 2287.7236, None, None, "cvms4", "cvms4", "cvms4", None, None)) sd_test = [SeismicData(Point(-130, 40, 0, UCVM_ELEVATION))] self.assertTrue( UCVM.query(sd_test, "cvms4.usgs-noaa.elevation", ["velocity", "elevation"])) # This is above sea level so it should be None for everything. assert_velocity_properties( self, sd_test[0], VelocityProperties(None, None, None, None, None, None, None, None, None, None)) self._test_end()
def test_bayarea_basic_elevation(self): """ Tests the Bay Area query capabilities using elevation. This uses the model's DEM, not the UCVM DEM. Returns: None """ self._test_start("test for Bay Area query by elevation") sd_test = [SeismicData(Point(-122.0322, 37.3230, 0, UCVM_ELEVATION))] self.assertTrue(UCVM.query(sd_test, "bayarea.elevation")) assert_velocity_properties( self, sd_test[0], VelocityProperties(1700.0, 390.0, 1990.0, 44.0, 22.0, "bayarea", "bayarea", "bayarea", "bayarea", "bayarea")) sd_test = [SeismicData(Point(-130, 40, 0, UCVM_ELEVATION))] self.assertTrue( UCVM.query(sd_test, "bayarea.elevation", ["velocity", "elevation"])) # This is above sea level so it should be None for everything. assert_velocity_properties( self, sd_test[0], VelocityProperties(None, None, None, None, None, None, None, None, None, None)) self._test_end()
def _set_velocity_properties_none(cls, sd: SeismicData) -> None: """ Helper method to set the SeismicData velocity properties to just be none (i.e. no material properties found). :param sd: The SeismicData object to set. :return: Nothing """ sd.set_velocity_data( VelocityProperties(None, None, None, None, None, None, None, None, None, None))
def _get_nationalmap_data(self, datum: SeismicData) -> bool: """ Attempts to get elevation properties from National Map data. If no properties can be found this function returns false. It does not set the properties to "None". Args: datum (SeismicData): The data point from which to get elevation properties. Returns: True, if successful, false if point not found within map. """ bilinear_point = SimplePoint(datum.converted_point.x_value, datum.converted_point.y_value, 0) if bilinear_point.x < -180 or bilinear_point.x > 180 or \ bilinear_point.y < -90 or bilinear_point.y > 90: return False # Make sure we can get the National Map data. if hasattr( self, "dem_nationalmap_" + str(-1 * math.floor(datum.converted_point.x_value)) + "_" + str(math.floor(datum.converted_point.y_value))): use_data = getattr( self, "dem_nationalmap_" + str(-1 * math.floor(datum.converted_point.x_value)) + "_" + str(math.floor(datum.converted_point.y_value))) else: if hasattr( self._opened_file, "dem_nationalmap_" + str(math.ceil(-1 * datum.converted_point.x_value)) + "_" + str(math.floor(datum.converted_point.y_value))): use_data = getattr( self._opened_file, "dem_nationalmap_" + str(-1 * math.floor(datum.converted_point.x_value)) + "_" + str(math.floor(datum.converted_point.y_value)))[:, :] else: return False rect = SimpleRotatedRectangle(use_data["metadata"][1][0], use_data["metadata"][2][0], 0, use_data["metadata"][0][0], use_data["metadata"][0][0]) value = calculate_bilinear_value(bilinear_point, rect, use_data.data) # Check if not defined by DEM (i.e. in water). if value == 0 or value == -9999: return False datum.set_elevation_data( ElevationProperties(value, self._public_metadata["id"])) return True
def _get_nationalmap_data(self, datum: SeismicData) -> bool: """ Attempts to get elevation properties from National Map data. If no properties can be found this function returns false. It does not set the properties to "None". Args: datum (SeismicData): The data point from which to get elevation properties. Returns: True, if successful, false if point not found within map. """ bilinear_point = SimplePoint( datum.converted_point.x_value, datum.converted_point.y_value, 0 ) if bilinear_point.x < -180 or bilinear_point.x > 180 or \ bilinear_point.y < -90 or bilinear_point.y > 90: return False # Make sure we can get the National Map data. if hasattr(self, "dem_nationalmap_" + str(-1 * math.floor(datum.converted_point.x_value)) + "_" + str(math.floor(datum.converted_point.y_value))): use_data = getattr(self, "dem_nationalmap_" + str(-1 * math.floor(datum.converted_point.x_value)) + "_" + str(math.floor(datum.converted_point.y_value))) else: if hasattr(self._opened_file, "dem_nationalmap_" + str(math.ceil(-1 * datum.converted_point.x_value)) + "_" + str(math.floor(datum.converted_point.y_value))): use_data = getattr(self._opened_file, "dem_nationalmap_" + str(-1 * math.floor(datum.converted_point.x_value)) + "_" + str(math.floor(datum.converted_point.y_value)))[:, :] else: return False rect = SimpleRotatedRectangle( use_data["metadata"][1][0], use_data["metadata"][2][0], 0, use_data["metadata"][0][0], use_data["metadata"][0][0] ) value = calculate_bilinear_value(bilinear_point, rect, use_data.data) # Check if not defined by DEM (i.e. in water). if value == 0 or value == -9999: return False datum.set_elevation_data(ElevationProperties(value, self._public_metadata["id"])) return True
def _set_velocity_properties_none(cls, sd: SeismicData) -> None: """ Helper method to set the SeismicData velocity properties to just be none (i.e. no material properties found). :param sd: The SeismicData object to set. :return: Nothing """ sd.set_velocity_data( VelocityProperties( None, None, None, None, None, None, None, None, None, None ) )
def test_cvmh_query_by_elevation(self): """ Tests the CVM-H query capabilities using the model's DEM. Returns: None """ self._test_start("test for CVM-H query using elevation") sd_test = [SeismicData(Point(-118, 34, 0, UCVM_ELEVATION))] self.assertTrue(UCVM.query(sd_test, "cvmh1510[gt].elevation")) assert_velocity_properties( self, sd_test[0], VelocityProperties(2495.1269, 978.5577, 2091.678, None, None, "cvmh1510", "cvmh1510", "cvmh1510", None, None)) sd_test = [SeismicData(Point(-118, 34, 0))] self.assertTrue(UCVM.query(sd_test, "cvmh1510[gtl]")) # Query by depth. assert_velocity_properties( self, sd_test[0], VelocityProperties(824.177, 195, 1084.062, None, None, "cvmh1510", "cvmh1510", "cvmh1510", None, None)) # Checks to see that the material properties returned at 266.690277 elevation at -118, 34 equal the # material properties returned at 0m depth (i.e. that CVM-H is using its own DEM correctly). sd_test = [ SeismicData(Point(-118, 34, 266.690277099609, UCVM_ELEVATION)) ] self.assertTrue(UCVM.query(sd_test, "cvmh1510[gtl].elevation")) assert_velocity_properties( self, sd_test[0], VelocityProperties(824.177, 195, 1084.062, None, None, "cvmh1510", "cvmh1510", "cvmh1510", None, None)) # Check to see that "air" returns nothing (there's a bug in vx that will return 1000 for density in air). sd_test = [SeismicData(Point(-118, 34, 1000, UCVM_ELEVATION))] self.assertTrue(UCVM.query(sd_test, "cvmh1510.elevation")) assert_velocity_properties( self, sd_test[0], VelocityProperties(None, None, None, None, None, None, None, None, None, None)) self._test_end()
def setUp(self) -> None: """ Set up all the initial SeismicData points. Returns: Nothing """ self.data = { "depth": [ SeismicData(Point(-118, 34, 0)), SeismicData(Point(-118, 34, 16)), SeismicData(Point(-118, 34, 20)), SeismicData(Point(-118, 34, 100000)) ] }
def test_cvms426_random_points(self): """ Tests the CVM-S4.26 velocity model at 10 random points selected from the model. These points were picked with a random number generator. Returns: None """ self._test_start("CVM-S4.26 points versus text model test") test_data = \ """ 90 754 10 -118.737022 32.944866 5571.414 3057.374 2792.542 724 627 15 -116.004835 34.763130 6383.228 3702.753 2863.826 449 125 19 -114.943019 32.340362 6094.292 3597.746 2817.387 924 1011 21 -116.896018 36.574456 5872.374 3248.397 2874.105 664 1416 22 -119.570398 36.833491 6357.490 3675.896 2882.698 385 1027 39 -118.869259 34.753449 6344.310 3578.079 2856.254 100 1496 43 -121.846471 35.058333 7403.315 4269.781 3034.174 689 567 48 -115.882460 34.466751 6493.230 3719.698 2909.571 361 850 49 -118.208090 34.163152 6771.910 3571.393 2953.548 444 723 53 -117.391091 34.083565 6937.791 4099.394 2912.123 736 901 56 -117.105324 35.607358 6727.089 3885.899 2943.158 949 1062 56 -117.023118 36.809121 6649.673 3770.664 2931.769 396 1061 69 -118.975273 34.888717 7781.172 4487.968 3095.297 558 1513 84 -120.364910 36.732035 7862.731 4538.450 3107.515 961 534 87 -114.765700 35.290399 7873.649 4544.644 3108.936 722 73 90 -113.767296 33.102653 7892.802 4558.516 3110.357 142 309 96 -116.744822 31.837443 7945.724 4599.341 3113.200 847 4 99 -113.043306 33.310262 7914.255 4569.352 3114.621 670 240 99 -114.620776 33.430007 7919.039 4574.102 3114.621 177 1240 100 -120.485602 34.623764 7869.447 4529.999 3115.094 """ points = [] for point in test_data.split("\n"): if point.strip() == "": continue point = point.split() points.append( (float(point[3]), float(point[4]), (int(point[2]) - 1) * 500, float(point[5]), float(point[6]), float(point[7])) ) sd_test = [SeismicData(Point(p[0], p[1], p[2])) for p in points] self.assertTrue(UCVM.query(sd_test, "cvms426", ["velocity"])) epsilon = 0.00001 for i in range(len(sd_test)): self.assertGreater(sd_test[i].velocity_properties.vp / points[i][3], 1 - epsilon) self.assertLess(sd_test[i].velocity_properties.vp / points[i][3], 1 + epsilon) self.assertGreater(sd_test[i].velocity_properties.vs / points[i][4], 1 - epsilon) self.assertLess(sd_test[i].velocity_properties.vs / points[i][4], 1 + epsilon) self.assertGreater(sd_test[i].velocity_properties.density / points[i][5], 1 - epsilon) self.assertLess(sd_test[i].velocity_properties.density / points[i][5], 1 + epsilon) self._test_end()
def _get_etopo1_data(self, datum: SeismicData) -> bool: """ Attempts to get elevation properties from ETOPO1 data. If no properties can be found this function returns false. It does not set the properties to "None". Args: datum (SeismicData): The data point from which to get elevation properties. Returns: True, if successful, false if point not found within map. """ datum.converted_point = datum.original_point.convert_to_projection(UCVM_DEFAULT_PROJECTION) bilinear_point = SimplePoint( datum.converted_point.x_value, datum.converted_point.y_value, 0 ) if not hasattr(self, "etopo1_data"): self.etopo1_data = self._opened_file["dem_etopo1"]["data"][:, :] self.etopo1_metadata = self._opened_file["dem_etopo1"]["metadata"][:, :] if bilinear_point.x < -180 or bilinear_point.x > 180 or \ bilinear_point.y < -90 or bilinear_point.y > 90: return False rect = SimpleRotatedRectangle( self.etopo1_metadata[1][0], self.etopo1_metadata[2][0], 0, self.etopo1_metadata[0][0], self.etopo1_metadata[0][0] ) datum.set_elevation_data(ElevationProperties( calculate_bilinear_value(bilinear_point, rect, self.etopo1_data), self._public_metadata["id"] )) return True
def create_max_seismicdata_array(cls, total_points: int=250000, processes: int=1) -> \ List[SeismicData]: """ Returns an array of SeismicData objects. :param total_points: The number of SeismicData tuples required. :param processes: TEST :return: A list of the SeismicData tuple objects. """ return [ SeismicData() for _ in range(0, cls._get_max_query(total_points, processes)) ]
def test_awp_rwg_equivalent(self): """ Quick verification that the AWP and RWG formats are equivalent (i.e. same material properties). """ sd_awp = [SeismicData(Point(-118, 34, 0)) for _ in range(0, 101505)] sd_rwg = [SeismicData(Point(-119, 35, 0)) for _ in range(0, 101505)] awp_im = InternalMesh.from_xml_file( os.path.join(self.dir, "data", "simple_mesh_ijk12_unrotated.xml") ) awp_iterator = AWPInternalMeshIterator(awp_im, 0, 101505, 101505, sd_awp) rwg_im = InternalMesh.from_xml_file( os.path.join(self.dir, "data", "simple_mesh_rwg_unrotated.xml") ) rwg_iterator = RWGInternalMeshIterator(rwg_im, 0, 101505, 101505, sd_rwg) next(awp_iterator) next(rwg_iterator) counter = 0 for item_awp in sd_awp: # For time reasons, don't test every point. Test every 250 points. if counter == 250: counter = 0 else: counter += 1 continue found = False for item_rwg in sd_rwg: if math.isclose(item_rwg.original_point.x_value, item_awp.original_point.x_value) and \ math.isclose(item_rwg.original_point.y_value, item_awp.original_point.y_value) and \ math.isclose(item_rwg.original_point.z_value, item_awp.original_point.z_value): found = True sd_rwg.remove(item_rwg) break if not found: print(item_awp.original_point.x_value, item_awp.original_point.y_value, item_awp.original_point.z_value) self.assertTrue(False) self.assertTrue(True)
def setUp(self): self.im_1 = InternalMesh.from_xml_file( os.path.join(self.dir, "data", "simple_mesh_ijk12_unrotated.xml") ) self.sd = [SeismicData(Point(-118, 34, 0)) for _ in range(0, 101505)] self.im_1.out_dir = os.path.join(self.dir, "scratch") self.im_1_iterator_1 = AWPInternalMeshIterator(self.im_1, 0, 101505, 1005, self.sd) self.im_1_iterator_2 = AWPInternalMeshIterator(self.im_1, 0, 101505, 101505, self.sd) self.im_2 = InternalMesh.from_xml_file( os.path.join(self.dir, "data", "simple_mesh_ijk12_rotated.xml") ) self.sd2 = [SeismicData(Point(-118, 34, 0)) for _ in range(0, 51005)] self.im_2.out_dir = os.path.join(self.dir, "scratch") self.im_2_iterator_1 = AWPInternalMeshIterator(self.im_2, 0, 51005, 505, self.sd2) self.im_2_iterator_2 = AWPInternalMeshIterator(self.im_2, 0, 51005, 51005, self.sd2) self.im_3 = InternalMesh.from_xml_file( os.path.join(self.dir, "data", "simple_utm_mesh_ijk12_rotated.xml") ) self.sd3 = [SeismicData(Point(-118, 34, 0)) for _ in range(0, 101505)] self.im_3.out_dir = os.path.join(self.dir, "scratch") self.im_3_iterator_1 = AWPInternalMeshIterator(self.im_3, 0, 101505, 202, self.sd3) self.im_3_iterator_2 = AWPInternalMeshIterator(self.im_3, 0, 101505, 101505, self.sd3)
def _get_etopo1_data(self, datum: SeismicData) -> bool: """ Attempts to get elevation properties from ETOPO1 data. If no properties can be found this function returns false. It does not set the properties to "None". Args: datum (SeismicData): The data point from which to get elevation properties. Returns: True, if successful, false if point not found within map. """ datum.converted_point = datum.original_point.convert_to_projection( UCVM_DEFAULT_PROJECTION) bilinear_point = SimplePoint(datum.converted_point.x_value, datum.converted_point.y_value, 0) if not hasattr(self, "etopo1_data"): self.etopo1_data = self._opened_file["dem_etopo1"]["data"][:, :] self.etopo1_metadata = self._opened_file["dem_etopo1"][ "metadata"][:, :] if bilinear_point.x < -180 or bilinear_point.x > 180 or \ bilinear_point.y < -90 or bilinear_point.y > 90: return False rect = SimpleRotatedRectangle(self.etopo1_metadata[1][0], self.etopo1_metadata[2][0], 0, self.etopo1_metadata[0][0], self.etopo1_metadata[0][0]) datum.set_elevation_data( ElevationProperties( calculate_bilinear_value(bilinear_point, rect, self.etopo1_data), self._public_metadata["id"])) return True
def _query(self, data: List[SeismicData], **kwargs) -> bool: """ This is the method that all models override. It handles querying the velocity model and filling in the SeismicData structures. Args: points (:obj:`list` of :obj:`SeismicData`): List of SeismicData objects containing the points. These are to be populated with :obj:`Vs30Properties`: Returns: True on success, false if there is an error. """ for datum in data: if datum.model_string is not None: query_points = [ SeismicData( Point(datum.original_point.x_value, datum.original_point.y_value, z, UCVM_DEPTH, datum.original_point.metadata, datum.original_point.projection)) for z in range(0, 30) ] for point in query_points: point.set_elevation_data(datum.elevation_properties) UCVM.query(query_points, datum.model_string, ["velocity"]) if query_points[0].velocity_properties.vs is None or \ query_points[0].velocity_properties.vs == 0: datum.vs30_properties = Vs30Properties(None, None) continue avg_slowness = 0 for point in query_points: avg_slowness += 1.0 / float(point.velocity_properties.vs) datum.vs30_properties = Vs30Properties( 1.0 / (avg_slowness / len(query_points)), self._public_metadata["id"]) else: datum.vs30_properties = Vs30Properties(None, None) return True
def test_falls_to_etopo_in_ocean(self): """ Tests that in the ocean - where the USGS map has no data - we fall back to the ETOPO1 map which has the bathymetry data in it. Returns: None """ self._test_start("test for ocean using ETOPO1 data") sd_test = [SeismicData(Point(-118.2, 33.5, 0))] self.assertTrue(UCVM.query(sd_test, "usgs-noaa", ["elevation"])) self.assertLess(sd_test[0].elevation_properties.elevation, 0) self.assertEqual(sd_test[0].elevation_properties.elevation_source, "usgs-noaa") self._test_end()
def mesh_extract_mpi(information: dict, start_end: tuple) -> bool: """ Extracts the parameters for the MPI process. Args: information (dict): The dictionary containing the metadata defining the extraction. start_end (tuple): The tuple defining the start and end poing. Returns: True, when successful. Raises an error if the extraction fails. """ from mpi4py import MPI comm = MPI.COMM_WORLD rank = comm.Get_rank() internal_mesh = InternalMesh(information) max_pts = 250000 sd_array = [SeismicData() for _ in range(0, max_pts)] print( "[Node %d] Responsible for extracting %d grid points. We can extract %d at once.\nStarting extraction..." % ( rank, start_end[1] - start_end[0], max_pts ), flush=True ) information["minimums"]["vp"] = float(information["minimums"]["vp"]) information["minimums"]["vs"] = float(information["minimums"]["vs"]) if information["format"] == "rwg": _mesh_extract_mpi_rwg(sd_array, information, internal_mesh, start_end) elif information["format"] == "awp": _mesh_extract_mpi_awp(sd_array, information, internal_mesh, start_end) else: raise ValueError("Invalid mesh format.") print( "[Node %d] Extraction is done!" % rank )
def run_acceptance_test(test_case: unittest.TestCase, model_id: str, props_to_test: list = None) -> bool: """ Runs the acceptance test for the given model id. :param test_case: The unittest case. :param model_id: The model ID to run the test for. :return: True if successful, false or exception if not. """ npy_test_file = os.path.join(UCVM_MODELS_DIRECTORY, model_id, "test_" + model_id + ".npy") ucvm_model_file = os.path.join(UCVM_MODELS_DIRECTORY, model_id, "ucvm_model.xml") spacing = 0.05 depth = 5000 bottom_corner = {"e": 0, "n": 0} if not os.path.exists(npy_test_file) or not os.path.exists( ucvm_model_file): return False with open(ucvm_model_file, "r") as fd: ucvm_model = xmltodict.parse(fd.read()) bottom_corner["e"] = \ float(ucvm_model["root"]["information"]["coverage"]["bottom-left"]["e"]) bottom_corner["n"] = \ float(ucvm_model["root"]["information"]["coverage"]["bottom-left"]["n"]) model_type = ucvm_model["root"]["information"]["type"] arr = np.load(npy_test_file) nums = {"x": len(arr), "y": len(arr[0]), "z": len(arr[0][0])} sd_array = [ SeismicData() for _ in range(nums["x"] * nums["y"] * nums["z"]) ] counter = 0 for z in range(nums["z"]): for y in range(nums["y"]): for x in range(nums["x"]): sd_array[counter].original_point = Point( bottom_corner["e"] + spacing * x, bottom_corner["n"] + spacing * y, 0 + depth * z) counter += 1 UCVM.query(sd_array, model_id, [model_type]) if props_to_test is None or len(props_to_test) == 0: props_to_test = ["vp", "vs", "density"] counter = 0 epsilon = 0.006 for z in range(nums["z"]): for y in range(nums["y"]): for x in range(nums["x"]): if arr[x][y][z][0] <= 0 and sd_array[counter].velocity_properties.vp is None or \ arr[x][y][z][1] <= 0 and sd_array[counter].velocity_properties.vs is None or \ arr[x][y][z][2] <= 0 and sd_array[counter].velocity_properties.density is None: counter += 1 continue # This is to account for a floating point rounding issue in the CVM-S4.26 test which has the new UCVM # thinking that the corner is in bounds and the old version thinking it's out of bounds. This version # thinks the point is 1534.999999999 where as the old version thinks it's exactly 1535. This also fixes # a difference whereby the old CVM-S5 extended below 50000km but the new one does not. if (sd_array[counter].original_point.x_value == -116 and sd_array[counter].original_point.y_value == 30.45 and model_id == "cvms426") or \ (sd_array[counter].original_point.z_value == 50000 and model_id == "cvms426"): counter += 1 continue if "vp" in props_to_test: test_case.assertGreater( sd_array[counter].velocity_properties.vp / arr[x][y][z][0], 1 - epsilon) test_case.assertLess( sd_array[counter].velocity_properties.vp / arr[x][y][z][0], 1 + epsilon) if "vs" in props_to_test: test_case.assertGreater( sd_array[counter].velocity_properties.vs / arr[x][y][z][1], 1 - epsilon) test_case.assertLess( sd_array[counter].velocity_properties.vs / arr[x][y][z][1], 1 + epsilon) if "density" in props_to_test: test_case.assertGreater( sd_array[counter].velocity_properties.density / arr[x][y][z][2], 1 - epsilon) test_case.assertLess( sd_array[counter].velocity_properties.density / arr[x][y][z][2], 1 + epsilon) counter += 1 return True
def _get_z_data(cls, p: Point, model: str, spacing: int = 50, depth: int = 70000) -> dict: """ Gets the Z1.0 and Z2.5 data for a given point which has all the projection, metadata, x, y, etc. specified. Args: p (Point): The point for which the Z1.0 and Z2.5 values should be found. model (str): The model to query to find the Z1.0 and Z2.5 at this point. spacing (int): The vertical spacing at which the queries should be made. The default is one meter. depth (int): Check for Vs values down to this depth. The default is 70 kilometers. Returns: dict: A dict containing the Z1.0 (first) and Z2.5 (second) when successful. None if an error occurs. """ _interval_size = 1000 _velocities_to_find = (1000, 2500) #This if statement is a toggle to select three different algorithms for finding Z-values: # 1st occurrence, 2nd occurrence, last occurrence (probably the same as 2nd for all 17.5 models) if False: #This one checks for 1st occurrence _current_interval = 0 _depths = {1000: depth, 2500: depth} while _current_interval < depth: _query_points = [ SeismicData( Point(p.x_value, p.y_value, _current_interval + (z * spacing), UCVM_DEPTH, None, p.projection)) for z in range(0, int(_interval_size / spacing) + 1) ] UCVM.query(_query_points, model.replace(".z-calc", ""), ["velocity"]) for target in _velocities_to_find: for point in _query_points: if point.velocity_properties is not None and point.velocity_properties.vs is not None: if point.velocity_properties.vs >= target and _depths[ target] == depth: _depths[target] = point.converted_point.z_value break if _depths[1000] != depth and _depths[2500] != depth: return _depths else: _current_interval += _interval_size elif False: #This one checks for last occurrence _current_interval = depth _depths = {1000: 0, 2500: 0} while _current_interval > 0: _query_points = [ SeismicData( Point(p.x_value, p.y_value, _current_interval - (z * spacing), UCVM_DEPTH, None, p.projection)) for z in range(0, int(_interval_size / spacing) + 1) ] UCVM.query(_query_points, model.replace(".z-calc", ""), ["velocity"]) for target in _velocities_to_find: for point in _query_points: if point.velocity_properties is not None and point.velocity_properties.vs is not None: if point.velocity_properties.vs <= target and _depths[ target] == 0: #This will give us the first point which is less than the target; we want the previous #(deeper) point to be consistent with Z2.5 def _depths[ target] = point.converted_point.z_value + spacing break if _depths[1000] != 0 and _depths[2500] != 0: return _depths else: _current_interval -= _interval_size else: #This one checks for 2nd occurrence _current_interval = 0 _depths = {1000: depth, 2500: depth} _flags = {1000: 0, 2500: 0} while _current_interval < depth: _query_points = [ SeismicData( Point(p.x_value, p.y_value, _current_interval + (z * spacing), UCVM_DEPTH, None, p.projection)) for z in range(0, int(_interval_size / spacing) + 1) ] UCVM.query(_query_points, model.replace(".z-calc", ""), ["velocity"]) for target in _velocities_to_find: for point in _query_points: if point.velocity_properties is not None and point.velocity_properties.vs is not None: if point.velocity_properties.vs >= target and _flags[ target] == 0: _depths[target] = point.converted_point.z_value _flags[target] = 1 elif point.velocity_properties.vs < target and _flags[ target] == 1: _flags[target] = 2 elif point.velocity_properties.vs >= target and _flags[ target] == 2: _depths[target] = point.converted_point.z_value _flags[target] = 3 break if _flags[2500] == 3: return _depths else: _current_interval += _interval_size #If we get here, we didn't find valid depths return _depths
def _query(self, data: List[SeismicData], **kwargs) -> bool: """ This is the method that all models override. It handles retrieving the queried models' properties and adjusting the SeismicData structures as need be. Args: points (:obj:`list` of :obj:`SeismicData`): List of SeismicData objects containing the points queried. These are to be adjusted if needed. Returns: True on success, false if there is an error. """ spacing = 500 if "params" in kwargs: if is_number(kwargs["params"]): spacing = kwargs["params"] proj_in = Proj(UCVM_DEFAULT_PROJECTION) for datum in data: proj_out = Proj( "+proj=utm +datum=WGS84 +zone=%d" % (get_utm_zone_for_lon(datum.converted_point.x_value))) utm_coords = transform(proj_in, proj_out, datum.converted_point.x_value, datum.converted_point.y_value) # Get the four corners. corners_utm_e = [ utm_coords[0] - spacing / 2, utm_coords[0] - spacing / 2, utm_coords[0] + spacing / 2, utm_coords[0] + spacing / 2 ] corners_utm_n = [ utm_coords[1] - spacing / 2, utm_coords[1] + spacing / 2, utm_coords[1] - spacing / 2, utm_coords[1] + spacing / 2 ] lat_lon_corners = transform(proj_out, proj_in, corners_utm_e, corners_utm_n) sd_array = [ SeismicData( Point(lat_lon_corners[0][0], lat_lon_corners[1][0], datum.original_point.z_value, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][1], lat_lon_corners[1][1], datum.original_point.z_value, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][2], lat_lon_corners[1][2], datum.original_point.z_value, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][3], lat_lon_corners[1][3], datum.original_point.z_value, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][0], lat_lon_corners[1][0], datum.original_point.z_value - spacing / 2, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][1], lat_lon_corners[1][1], datum.original_point.z_value - spacing / 2, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][2], lat_lon_corners[1][2], datum.original_point.z_value - spacing / 2, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][3], lat_lon_corners[1][3], datum.original_point.z_value - spacing / 2, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][0], lat_lon_corners[1][0], datum.original_point.z_value + spacing / 2, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][1], lat_lon_corners[1][1], datum.original_point.z_value + spacing / 2, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][2], lat_lon_corners[1][2], datum.original_point.z_value + spacing / 2, datum.original_point.depth_elev)), SeismicData( Point(lat_lon_corners[0][3], lat_lon_corners[1][3], datum.original_point.z_value + spacing / 2, datum.original_point.depth_elev)), ] # Now query for the material properties. UCVM.query(sd_array, datum.model_string, ["velocity"]) def contains_num_in_range( num_list: List(int), start_index: int, stop_index: int): for item in num_list: if start_index <= item <= stop_index: return True return False model_string_differences = [] for i in range(len(sd_array)): if sd_array[i].model_string != datum.model_string: model_string_differences.append(i) if sd_array[4].is_property_type_set("velocity") and \ sd_array[5].is_property_type_set("velocity") and \ sd_array[6].is_property_type_set("velocity") and \ sd_array[7].is_property_type_set("velocity") and \ sd_array[8].is_property_type_set("velocity") and \ sd_array[9].is_property_type_set("velocity") and \ sd_array[10].is_property_type_set("velocity") and \ sd_array[11].is_property_type_set("velocity") and \ contains_num_in_range(model_string_differences, 4, 11): datum.set_velocity_data( self._interpolate_properties(sd_array[4:11])) elif sd_array[0].is_property_type_set("velocity") and \ sd_array[1].is_property_type_set("velocity") and \ sd_array[2].is_property_type_set("velocity") and \ sd_array[3].is_property_type_set("velocity") and \ contains_num_in_range(model_string_differences, 0, 3): datum.set_velocity_data( self._interpolate_properties(sd_array[0:3])) return True
def _query(self, data: List[SeismicData], **kwargs) -> bool: """ This is the method that all models override. It handles retrieving the queried models' properties and adjusting the SeismicData structures as need be. Args: points (:obj:`list` of :obj:`SeismicData`): List of SeismicData objects containing the points queried. These are to be adjusted if needed. Returns: True on success, false if there is an error. """ ely_coefficients = {"a": 1 / 2, "b": 2 / 3, "c": 3 / 2} depth = 350 zmin = 0 for datum in data: if datum.velocity_properties is None or \ datum.velocity_properties.vs is None or datum.velocity_properties.vs == 0 or \ datum.velocity_properties.vp is None or datum.velocity_properties.vp == 0 or \ datum.velocity_properties.density is None or datum.velocity_properties.density == 0 or \ datum.vs30_properties is None or datum.vs30_properties.vs30 == 0 or datum.vs30_properties.vs30 is None: continue if datum.converted_point.z_value < zmin: new_vs = ely_coefficients["a"] * datum.vs30_properties.vs30 new_vp = ely_coefficients["a"] * calculate_scaled_vp(new_vs) new_dn = calculate_nafe_drake_density(new_vp) datum.set_velocity_data( VelocityProperties(new_vp, new_vs, new_dn, datum.velocity_properties.qp, datum.velocity_properties.qs, new_sources["vp"], new_sources["vs"], new_sources["dn"], datum.velocity_properties.qp_source, datum.velocity_properties.qs_source)) elif datum.converted_point.z_value < depth: datum_ely = [ SeismicData( Point(datum.converted_point.x_value, datum.converted_point.y_value, depth, UCVM_DEPTH, datum.converted_point.projection)) ] UCVM.query( datum_ely, datum.model_string.replace(".elevation", "").replace(".elygtl", ""), ["velocity"]) new_vs = datum_ely[0].velocity_properties.vs new_vp = datum_ely[0].velocity_properties.vp new_dn = datum_ely[0].velocity_properties.density new_sources = { "vp": datum_ely[0].velocity_properties.vp_source, "vs": datum_ely[0].velocity_properties.vs_source, "dn": datum_ely[0].velocity_properties.density_source } z = (datum.converted_point.z_value - zmin) / (depth - zmin) f = z - math.pow(z, 2.0) g = math.pow(z, 2.0) + 2 * math.pow(z, 0.5) - (3 * z) new_vs = (z + ely_coefficients["b"] * f) * new_vs + \ (ely_coefficients["a"] - ely_coefficients["a"] * z + ely_coefficients["c"] * g) * datum.vs30_properties.vs30 new_vp = (z + ely_coefficients["b"] * f) * new_vp + \ (ely_coefficients["a"] - ely_coefficients["a"] * z + ely_coefficients["c"] * g) * \ calculate_scaled_vp(datum.vs30_properties.vs30) new_dn = calculate_nafe_drake_density(new_vp) for key, item in new_sources.items(): new_sources[key] = \ ", ".join([x.strip() for x in new_sources[key].split(",")]) + ", Ely GTL" datum.set_velocity_data( VelocityProperties(new_vp, new_vs, new_dn, datum.velocity_properties.qp, datum.velocity_properties.qs, new_sources["vp"], new_sources["vs"], new_sources["dn"], datum.velocity_properties.qp_source, datum.velocity_properties.qs_source)) return True
def extract(self): proj = pyproj.Proj(proj='utm', zone=11, ellps='WGS84') x1, y1 = proj(self.start_point.x_value, self.start_point.y_value) x2, y2 = proj(self.end_point.x_value, self.end_point.y_value) num_prof = int( math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) / self.cross_section_properties.width_spacing) for j in range( int(self.start_point.z_value), int(self.end_point.z_value) + (1 if self.end_point.depth_elev == UCVM_DEPTH else -1), int(self.cross_section_properties.height_spacing)): for i in range(0, num_prof + 1): x = x1 + i * (x2 - x1) / float(num_prof) y = y1 + i * (y2 - y1) / float(num_prof) lon, lat = proj(x, y, inverse=True) self.sd_array.append( SeismicData( Point(lon, lat, j, int(self.start_point.depth_elev)))) UCVM.query(self.sd_array, self.cvms, ["elevation", "velocity"]) num_x = num_prof + 1 num_y = int( math.ceil(self.end_point.z_value - self.start_point.z_value) / self.cross_section_properties.height_spacing) self.extracted_data = np.arange(num_x * num_y * 6, dtype=float).reshape(num_y, num_x * 6) for y in range(int(num_y)): for x in range(int(num_x)): x_val = x * 6 if self.sd_array[y * num_x + x].velocity_properties is not None: vp_val = self.sd_array[y * num_x + x].velocity_properties.vp vs_val = self.sd_array[y * num_x + x].velocity_properties.vs density_val = self.sd_array[y * num_x + x].velocity_properties.density qp_val = self.sd_array[y * num_x + x].velocity_properties.qp qs_val = self.sd_array[y * num_x + x].velocity_properties.qs else: vp_val = None vs_val = None density_val = None qp_val = None qs_val = None self.extracted_data[y][ x_val] = vp_val if vp_val is not None else -1 self.extracted_data[y][ x_val + 1] = vs_val if vs_val is not None else -1 self.extracted_data[y][ x_val + 2] = density_val if density_val is not None else -1 self.extracted_data[y][ x_val + 3] = qp_val if qp_val is not None else -1 self.extracted_data[y][ x_val + 4] = qs_val if qs_val is not None else -1 if self.sd_array[y * num_x + x].elevation_properties is not None: self.extracted_data[y][x_val + 5] = \ self.sd_array[y * num_x + x].elevation_properties.elevation else: self.extracted_data[y][x_val + 5] = -1
def test_cca06_random_points(self): """ Tests the CCA06 velocity model at 10 random points selected from the model. These points were picked with a random number generator. Returns: None """ self._test_start("CCA06 points versus text model test") test_data = \ """ 438 254 5 -118.887875 35.478906 4895.436 2667.120 2435.278 46 796 5 -122.422779 36.382854 2429.266 1417.205 2241.661 335 108 8 -118.879781 34.674750 5172.307 2793.584 2480.476 566 730 13 -119.865852 37.552742 6236.374 3768.482 2791.083 951 7 19 -115.790940 35.880222 5989.860 3398.884 2668.398 963 7 27 -115.735974 35.910148 6137.117 3460.438 2692.684 954 887 31 -118.588744 39.145429 6179.948 3394.584 2665.174 234 495 49 -120.580990 35.813587 6534.183 3684.867 2791.827 447 679 49 -120.236755 37.050627 6946.152 4085.203 3005.396 339 616 55 -120.513406 36.533256 6727.385 3888.453 2922.629 987 167 58 -116.119090 36.566131 6582.264 3690.730 2803.978 139 137 66 -119.834750 34.261905 8074.908 4733.310 3348.805 532 82 68 -117.920905 35.092949 7987.021 4711.226 3343.804 968 586 68 -117.534766 38.072441 7602.601 4214.103 3079.460 574 40 72 -117.600991 35.046711 7739.257 4522.150 3249.446 369 337 75 -119.463563 35.600098 7765.333 4526.807 3250.931 156 149 90 -119.798850 34.350777 7970.437 4622.248 3294.685 226 496 92 -120.619796 35.795691 7765.998 4442.617 3200.752 5 522 96 -121.679680 35.290345 7905.824 4564.610 3270.179 778 154 97 -117.036585 35.990024 7867.409 4607.975 3291.877 """ points = [] for point in test_data.split("\n"): if point.strip() == "": continue point = point.split() points.append( (float(point[3]), float(point[4]), (int(point[2]) - 1) * 500, float(point[5]), float(point[6]), float(point[7]))) sd_test = [SeismicData(Point(p[0], p[1], p[2])) for p in points] self.assertTrue(UCVM.query(sd_test, "cca06", ["velocity"])) epsilon = 0.00001 for i in range(len(sd_test)): self.assertGreater( sd_test[i].velocity_properties.vp / points[i][3], 1 - epsilon) self.assertLess(sd_test[i].velocity_properties.vp / points[i][3], 1 + epsilon) self.assertGreater( sd_test[i].velocity_properties.vs / points[i][4], 1 - epsilon) self.assertLess(sd_test[i].velocity_properties.vs / points[i][4], 1 + epsilon) self.assertGreater( sd_test[i].velocity_properties.density / points[i][5], 1 - epsilon) self.assertLess( sd_test[i].velocity_properties.density / points[i][5], 1 + epsilon) self._test_end()
def extract(self): init_array = [SeismicData() for _ in range(0, 250000)] im = InternalMesh.from_parameters( self.origin, { "num_x": self.slice_properties.num_x, "num_y": self.slice_properties.num_y, "num_z": 1, "rotation": self.slice_properties.rotation, "spacing": self.slice_properties.spacing, "projection": self.origin.projection }, self.cvms, "") im_iterator = AWPInternalMeshIterator(im, 0, im.total_size, len(init_array), init_array) print("Beginning extraction...") counter = 0 total_counter = 0 num_queried = next(im_iterator) while num_queried > 0: if self.extras["plot"]["property"] == "elevation": UCVM.query(init_array[0:num_queried], self.cvms, ["elevation"]) for sd_prop in init_array[0:num_queried]: self.extracted_data[ counter] = sd_prop.elevation_properties.elevation counter += 1 elif self.extras["plot"]["property"] == "vs30": UCVM.query(init_array[0:num_queried], self.cvms, ["vs30", "elevation", "velocity"]) for sd_prop in init_array[0:num_queried]: self.extracted_data[counter] = sd_prop.vs30_properties.vs30 counter += 1 elif self.extras["plot"]["property"] == "z10" or self.extras[ "plot"]["property"] == "z25": if "z-calc" not in self.cvms: self.cvms += ".z-calc" UCVM.query(init_array[0:num_queried], self.cvms, ["velocity"]) for sd_prop in init_array[0:num_queried]: if sd_prop.z_properties is not None: self.extracted_data[counter] = sd_prop.z_properties.z10 self.extracted_data[counter + 1] = sd_prop.z_properties.z25 else: self.extracted_data[counter] = None self.extracted_data[counter + 1] = None counter += 2 else: UCVM.query(init_array[0:num_queried], self.cvms, ["elevation", "velocity"]) for sd_prop in init_array[0:num_queried]: self.extracted_data[ counter] = sd_prop.velocity_properties.vp self.extracted_data[counter + 1] = sd_prop.velocity_properties.vs self.extracted_data[ counter + 2] = sd_prop.velocity_properties.density self.extracted_data[counter + 3] = sd_prop.velocity_properties.qp self.extracted_data[counter + 4] = sd_prop.velocity_properties.qs self.extracted_data[ counter + 5] = sd_prop.elevation_properties.elevation counter += 6 total_counter += num_queried print("\t%.2f%% extracted." % ((total_counter / im.total_size) * 100)) try: num_queried = next(im_iterator) except StopIteration: break print("Done extracting %d points." % im.total_size)