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_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_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 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_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_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 from_dictionary(cls, dictionary: dict): start_point = Point(float(dictionary["start_point"]["x"]), float(dictionary["start_point"]["y"]), float(dictionary["start_point"]["z"]), int(dictionary["start_point"]["depth_elev"]), {}, dictionary["start_point"]["projection"]) end_point = Point(float(dictionary["end_point"]["x"]), float(dictionary["end_point"]["y"]), float(dictionary["end_point"]["z"]), int(dictionary["end_point"]["depth_elev"]), {}, dictionary["end_point"]["projection"]) cross_section_properties = CrossSectionProperties( float(dictionary["cross_section_properties"]["width_spacing"]), float(dictionary["cross_section_properties"]["height_spacing"]) if int(dictionary["start_point"]["depth_elev"]) == UCVM_DEPTH else -1 * float(dictionary["cross_section_properties"]["height_spacing"]), dictionary["cross_section_properties"]["property"]) cvm_list = dictionary["cvm_list"] if int(dictionary["end_point"] ["depth_elev"]) == UCVM_ELEVATION and ".depth" not in cvm_list: cvm_list += ".elevation" plot_properties = dictionary["plot"] data_properties = dictionary["data"] return CrossSection(start_point, end_point, cross_section_properties, cvm_list, plot=plot_properties, data=data_properties)
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_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_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_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 vpvs_ratio_test(_: unittest.TestCase): granularity = 0.001 depth_spacing = 10000 counter = 0 sd_array = UCVM.create_max_seismicdata_array() for x_val in \ custom_range(float(target.corners["bl"]["e"]), float(target.corners["tr"]["e"]) + granularity, granularity): for y_val in \ custom_range(float(target.corners["bl"]["n"]), float(target.corners["tr"]["n"]) + granularity, granularity): for z_val in custom_range(0, target.max_depth + depth_spacing, depth_spacing): sd_array[counter].original_point = Point( x_val, y_val, z_val) sd_array[counter].converted_point = Point( x_val, y_val, z_val) if counter == len(sd_array) - 1: UCVM.query(sd_array, name, ["velocity"]) _test_vpvs_ratio(sd_array) counter = 0 else: counter += 1 _test_vpvs_ratio(sd_array[0:counter])
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 __init__(self, mesh_info: dict): """ Returns an InternalMesh object which is an internal representation of what we want our mesh to be (i.e. all the grid points we need to query). Args: mesh_info (dict): The mesh info parsed from the XML file. """ if mesh_info is None: return try: depth_elev = int(mesh_info["initial_point"]["depth_elev"]) except ValueError: depth_elev = UCVM_ELEVATION if str(mesh_info["initial_point"]["depth_elev"]).\ strip().lower() == "elevation" else UCVM_DEPTH origin = Point(mesh_info["initial_point"]["x"], mesh_info["initial_point"]["y"], mesh_info["initial_point"]["z"], depth_elev, {}, mesh_info["initial_point"]["projection"]) self.origin = origin.convert_to_projection(mesh_info["projection"]) self.rotation = float(mesh_info["rotation"]) * -1 self.num_x = int(mesh_info["dimensions"]["x"]) self.num_y = int(mesh_info["dimensions"]["y"]) self.num_z = int(mesh_info["dimensions"]["z"]) self.spacing = float(mesh_info["spacing"]) self.grid_type = mesh_info["grid_type"] self.format = mesh_info["format"] self.cvm_list = mesh_info["cvm_list"] self.out_dir = mesh_info["out_dir"] self.projection = mesh_info["projection"] if self.format == "awp": self.slice_size = self.num_x * self.num_y self.total_size = self.slice_size * self.num_z elif self.format == "rwg": self.slice_size = self.num_x * self.num_z self.total_size = self.slice_size * self.num_y # Pre-compute this for efficiency. self.sin_angle = math.sin(math.radians(self.rotation)) self.cos_angle = math.cos(math.radians(self.rotation)) self.full_size = None self.start_point = 0 self.end_point = self.total_size
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 from_dictionary(cls, dictionary: dict): profile_point = Point( dictionary["profile_point"]["x"], dictionary["profile_point"]["y"], dictionary["profile_point"]["z"], UCVM_DEPTH if dictionary["profile_point"]["depth_elev"] == 0 or dictionary["profile_point"]["depth_elev"] == "0" else UCVM_ELEVATION, {}, dictionary["profile_point"]["projection"] ) depth_profile_properties = DepthProfileProperties( float(dictionary["profile_properties"]["depth"]), float(dictionary["profile_properties"]["spacing"]), [x.strip() for x in str(dictionary["profile_properties"]["properties"]).split(",")] ) cvm_list = dictionary["cvm_list"] if int(dictionary["profile_point"]["depth_elev"]) == UCVM_ELEVATION and ".depth" not in cvm_list: cvm_list += ".elevation" return DepthProfile( profile_point, depth_profile_properties, cvm_list, plot=dictionary["plot"], data=dictionary["data"] )
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 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 _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 from_dictionary(cls, parsed_dictionary: dict): """ From a dictionary, return an instance of the HorizontalSlice class. Note that you will still need to call extract and the other functions separately. This just configures everything. :param parsed_dictionary: The already parsed dictionary. :return: An instance of HorizontalSlice """ origin_point = Point( float(parsed_dictionary["bottom_left_point"]["x"]), float(parsed_dictionary["bottom_left_point"]["y"]), float(parsed_dictionary["bottom_left_point"]["z"]), int(parsed_dictionary["bottom_left_point"]["depth_elev"]), {}, parsed_dictionary["bottom_left_point"]["projection"]) slice_properties = SliceProperties( num_x=int(parsed_dictionary["properties"]["num_x"]), num_y=int(parsed_dictionary["properties"]["num_y"]), spacing=float(parsed_dictionary["properties"]["spacing"]), rotation=float(parsed_dictionary["properties"]["rotation"])) cvm_list = parsed_dictionary["cvm_list"] if int(parsed_dictionary["bottom_left_point"] ["depth_elev"]) == UCVM_ELEVATION and ".depth" not in cvm_list: cvm_list += ".elevation" plot_properties = parsed_dictionary["plot"] data_properties = parsed_dictionary["data"] # try: # save_file = parsed_dictionary["data"]["save"] # except KeyError: # save_file = None return HorizontalSlice(origin_point, slice_properties, cvm_list, plot=plot_properties, data=data_properties)
def _initialize(self, xml_file) -> None: """ Initialization helper function. This reads in the tags from the XML file and sets all the variables. Args: xml_file (dict): The already-parsed XML file as a dictionary. Returns: Nothing """ self.source = xml_file[ "mesh_name"] if "mesh_name" in xml_file else xml_file["etree_name"] if "initial_point" in xml_file: self.llcorner = Point( xml_file["initial_point"]["x"], xml_file["initial_point"]["y"], xml_file["initial_point"]["z"], UCVM_ELEVATION if str(xml_file["initial_point"]["depth_elev"]).lower() == "elevation" else UCVM_DEPTH, UCVM_DEFAULT_PROJECTION if str(xml_file["initial_point"]["projection"]).lower() == "default" else str(xml_file["initial_point"]["projection"])) self.dims = { "x": int(xml_file["dimensions"]["x"]), "y": int(xml_file["dimensions"]["y"]), "z": int(xml_file["dimensions"]["z"]), "spacing": int(xml_file["spacing"]) } self.rotation = float(xml_file["rotation"]) self.cos = float(math.cos(math.radians(self.rotation))) self.sin = float(math.sin(math.radians(self.rotation))) self.projection = xml_file["projection"] # Find the origin point. p1 = pyproj.Proj(self.llcorner.projection) p2 = pyproj.Proj(self.projection) ll_x, ll_y = pyproj.transform(p1, p2, self.llcorner.x_value, self.llcorner.y_value) self.origin_in_mesh_proj = [ll_x, ll_y] # Get the four corners. p1 = pyproj.Proj(UCVM_DEFAULT_PROJECTION) p2 = pyproj.Proj("+proj=utm +datum=WGS84 +zone=11") ll_x, ll_y = pyproj.transform(p1, p2, self.llcorner.x_value, self.llcorner.y_value) corners_e = (ll_x, ll_x, ll_x + self.dims["x"] * self.dims["spacing"], ll_x + self.dims["x"] * self.dims["spacing"]) corners_n = (ll_y, ll_y + self.dims["y"] * self.dims["spacing"], ll_y + self.dims["y"] * self.dims["spacing"], ll_y) corners_e, corners_n = pyproj.transform(p2, p1, corners_e, corners_n) self.corners = ((corners_e[0], corners_n[0]), (corners_e[1], corners_n[1]), (corners_e[2], corners_n[2]), (corners_e[3], corners_n[3])) else: self.corners = ((float(xml_file["corners"]["bl"]["x"]), float(xml_file["corners"]["bl"]["y"])), (float(xml_file["corners"]["ul"]["x"]), float(xml_file["corners"]["ul"]["y"])), (float(xml_file["corners"]["ur"]["x"]), float(xml_file["corners"]["ur"]["y"])), (float(xml_file["corners"]["br"]["x"]), float(xml_file["corners"]["br"]["y"])))
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()