From c6c93a804e5e7005b63e69bd0d35f796a0789b27 Mon Sep 17 00:00:00 2001 From: g-weatherill Date: Wed, 26 May 2021 15:47:51 +0200 Subject: [PATCH 1/6] Enables calculations of shakemaps across antimeridian --- shakyground2/shakemap.py | 42 +++++++++++++++++++++++++++----------- shakyground2/site_model.py | 25 +++++++++++++++++++---- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/shakyground2/shakemap.py b/shakyground2/shakemap.py index a15a984..63f34ba 100644 --- a/shakyground2/shakemap.py +++ b/shakyground2/shakemap.py @@ -357,8 +357,12 @@ class Shakemap(object): * rasterio.transform.Affine.scale(spcx, spcy) ) # Export to file + kwargs0 = {"height": results.shape[0], "width": results.shape[1], + "count": 1, "dtype": results.dtype, + "transform": transform, "crs": "+proj=latlong", + "compress": "lzw"} if filename: - with rasterio.open( + with rasterio.open(filename, "w", "GTiff", **kwargs0): filename, "w", "GTiff", @@ -370,21 +374,33 @@ class Shakemap(object): transform=transform, compress="lzw", ) as dst: - dst.write(results, 1) + if self.site_model.cross_antimeridian: + reproj_results = np.zeros(results.shape) + reproject(results, reproj_results, + src_transform=kwargs0["transform"], + src_crs = kwargs0["crs"], + dst_transform=kwargs0["transform"], + dst_crs = kwargs0["crs"], + kwargs={"CENTER_LONG": 180}) + dst.write(reproj_results, 1) + else: + dst.write(results, 1) return # Returns a bytes object with rasterio.MemoryFile(ext=".tif") as memfile: - with memfile.open( - driver="GTiff", - height=results.shape[0], - width=results.shape[1], - count=1, - dtype=results.dtype, - crs="+proj=latlong", - transform=transform, - compress="lzw", + with memfile.open(driver="GTiff", **kwargs0): ) as dst: - dst.write(results, 1) + if self.site_model.cross_antimeridian: + reproj_results = np.zeros(results.shape) + reproject(results, reproj_results, + src_transform=kwargs0["transform"], + src_crs = kwargs0["crs"], + dst_transform=kwargs0["transform"], + dst_crs = kwargs0["crs"], + kwargs={"CENTER_LONG": 180}) + dst.write(reproj_results, 1) + else: + dst.write(results, 1) buffer = memfile.getbuffer() io_buffer = io.BytesIO(buffer) @@ -460,6 +476,8 @@ class Shakemap(object): self.site_model.bbox_properties["ncol"], ] lons = self.site_model["lon"].reshape(new_shape) + if self.site_model.cross_antimeridian: + lons[lons < -180.0] += 360.0 lats = self.site_model["lat"].reshape(new_shape) # Surpress plotting plt.ioff() diff --git a/shakyground2/site_model.py b/shakyground2/site_model.py index 7ce9daa..686169c 100644 --- a/shakyground2/site_model.py +++ b/shakyground2/site_model.py @@ -46,12 +46,18 @@ class SiteModel(object): site_array: Array of sites and their corresponding properties as numpy.ndarray bbox_properties: Properties of the bounding box used to create the site array (where relevant) + cross_antimeridian: Indicates that the site model crosses the antimeridian (True) or + not (False) """ def __init__(self, site_array: np.ndarray, bbox_properties: Dict = {}): self.site_array = site_array + if "cross_antimeridian" in bbox_properties: + self.cross_antimeridian = bbox_properties.pop("cross_antimeridian") + else: + self.cross_antimeridian = False self.bbox_properties = bbox_properties - + def __len__(self): # Returns the number of sites in the site array return self.site_array.shape[0] @@ -155,9 +161,19 @@ class SiteModel(object): # Generate the mesh of points llon, llat, ulon, ulat = bbox - lons, lats = np.meshgrid( - np.arange(llon, ulon + spcx, spcx), np.arange(llat, ulat + spcy, spcy) - ) + if (llon > ulon) and (np.fabs(llon - ulon) > 180.0): + # Bounding box crosses the antimeridian + lons, lats = np.meshgrid( + np.arange(llon, ulon + 360.0 + spcx, spcx), np.arange(llat, ulat + spcy, spcy) + ) + cross_antimeridian = True + lons[lons > 180.0] -= 360.0 + else: + + lons, lats = np.meshgrid( + np.arange(llon, ulon + spcx, spcx), np.arange(llat, ulat + spcy, spcy) + ) + cross_antimeridian = False nrow, ncol = lons.shape nsites = nrow * ncol self = object.__new__(cls) @@ -169,6 +185,7 @@ class SiteModel(object): "spcy": spcy, "ncol": ncol, "nrow": nrow, + "cross_antimeridian": cross_antimeridian } # Site array has a set of defined datatypes site_dtype = np.dtype(list(SITE_PROPERTIES.items())) -- GitLab From 9a7813fc106065e3d28f2704c52f0db152172f79 Mon Sep 17 00:00:00 2001 From: g-weatherill Date: Thu, 27 May 2021 16:46:38 +0200 Subject: [PATCH 2/6] Potential fix of shakemap failing when crossing antimeridian --- shakyground2/shakemap.py | 62 ++++++++++----------- shakyground2/site_model.py | 6 +- shakyground2/synthetic_rupture_generator.py | 17 ++++-- shakyground2/workflows.py | 2 + tests/data/gfz2021jqav.xml | 1 + tests/site_model_test.py | 46 +++++++++++++++ tests/workflows_test.py | 12 ++++ 7 files changed, 108 insertions(+), 38 deletions(-) create mode 100644 tests/data/gfz2021jqav.xml diff --git a/shakyground2/shakemap.py b/shakyground2/shakemap.py index 63f34ba..f274211 100644 --- a/shakyground2/shakemap.py +++ b/shakyground2/shakemap.py @@ -10,6 +10,7 @@ import geopandas as gpd import matplotlib.pyplot as plt from typing import Dict, Optional, Tuple, List, Union from shapely.geometry import LineString, MultiLineString +from rasterio.warp import reproject from openquake.hazardlib import const, imt from openquake.hazardlib.contexts import ContextMaker from shakyground2 import valid @@ -357,47 +358,46 @@ class Shakemap(object): * rasterio.transform.Affine.scale(spcx, spcy) ) # Export to file - kwargs0 = {"height": results.shape[0], "width": results.shape[1], - "count": 1, "dtype": results.dtype, - "transform": transform, "crs": "+proj=latlong", - "compress": "lzw"} + kwargs0 = { + "height": results.shape[0], + "width": results.shape[1], + "count": 1, + "dtype": results.dtype, + "transform": transform, + "crs": "+proj=latlong", + "compress": "lzw", + } if filename: - with rasterio.open(filename, "w", "GTiff", **kwargs0): - filename, - "w", - "GTiff", - height=results.shape[0], - width=results.shape[1], - count=1, - dtype=results.dtype, - crs="+proj=latlong", - transform=transform, - compress="lzw", - ) as dst: + with rasterio.open(filename, "w", "GTiff", **kwargs0) as dst: if self.site_model.cross_antimeridian: reproj_results = np.zeros(results.shape) - reproject(results, reproj_results, - src_transform=kwargs0["transform"], - src_crs = kwargs0["crs"], - dst_transform=kwargs0["transform"], - dst_crs = kwargs0["crs"], - kwargs={"CENTER_LONG": 180}) + reproject( + results, + reproj_results, + src_transform=kwargs0["transform"], + src_crs=kwargs0["crs"], + dst_transform=kwargs0["transform"], + dst_crs=kwargs0["crs"], + kwargs={"CENTER_LONG": 180}, + ) dst.write(reproj_results, 1) else: dst.write(results, 1) return # Returns a bytes object with rasterio.MemoryFile(ext=".tif") as memfile: - with memfile.open(driver="GTiff", **kwargs0): - ) as dst: + with memfile.open(driver="GTiff", **kwargs0) as dst: if self.site_model.cross_antimeridian: reproj_results = np.zeros(results.shape) - reproject(results, reproj_results, - src_transform=kwargs0["transform"], - src_crs = kwargs0["crs"], - dst_transform=kwargs0["transform"], - dst_crs = kwargs0["crs"], - kwargs={"CENTER_LONG": 180}) + reproject( + results, + reproj_results, + src_transform=kwargs0["transform"], + src_crs=kwargs0["crs"], + dst_transform=kwargs0["transform"], + dst_crs=kwargs0["crs"], + kwargs={"CENTER_LONG": 180}, + ) dst.write(reproj_results, 1) else: dst.write(results, 1) @@ -477,7 +477,7 @@ class Shakemap(object): ] lons = self.site_model["lon"].reshape(new_shape) if self.site_model.cross_antimeridian: - lons[lons < -180.0] += 360.0 + lons[lons < 0] += 360.0 lats = self.site_model["lat"].reshape(new_shape) # Surpress plotting plt.ioff() diff --git a/shakyground2/site_model.py b/shakyground2/site_model.py index 686169c..8462915 100644 --- a/shakyground2/site_model.py +++ b/shakyground2/site_model.py @@ -57,7 +57,7 @@ class SiteModel(object): else: self.cross_antimeridian = False self.bbox_properties = bbox_properties - + def __len__(self): # Returns the number of sites in the site array return self.site_array.shape[0] @@ -169,7 +169,7 @@ class SiteModel(object): cross_antimeridian = True lons[lons > 180.0] -= 360.0 else: - + lons, lats = np.meshgrid( np.arange(llon, ulon + spcx, spcx), np.arange(llat, ulat + spcy, spcy) ) @@ -185,7 +185,7 @@ class SiteModel(object): "spcy": spcy, "ncol": ncol, "nrow": nrow, - "cross_antimeridian": cross_antimeridian + "cross_antimeridian": cross_antimeridian, } # Site array has a set of defined datatypes site_dtype = np.dtype(list(SITE_PROPERTIES.items())) diff --git a/shakyground2/synthetic_rupture_generator.py b/shakyground2/synthetic_rupture_generator.py index f914481..8081e99 100644 --- a/shakyground2/synthetic_rupture_generator.py +++ b/shakyground2/synthetic_rupture_generator.py @@ -117,10 +117,19 @@ class FiniteRuptureSampler(object): # the hypocentre spaced every 0.05 degrees - longer distances are less likely # to be significantly influenced by uncertainties in the rupture plane llon, llat, ulon, ulat = earthquake.get_maximum_distance_bbox(maximum_site_distance) - target_lons, target_lats = np.meshgrid( - np.arange(llon, ulon + site_spacing, site_spacing), - np.arange(llat, ulat + site_spacing, site_spacing), - ) + if ulon < llon: + # Happens when crosses the antimeridian + target_lons, target_lats = np.meshgrid( + np.arange(llon, ulon + 360.0 + site_spacing, site_spacing), + np.arange(llat, ulat + site_spacing, site_spacing), + ) + target_lons[target_lons > 180.0] -= 360.0 + else: + target_lons, target_lats = np.meshgrid( + np.arange(llon, ulon + site_spacing, site_spacing), + np.arange(llat, ulat + site_spacing, site_spacing), + ) + target_lons[target_lons > 180.0] -= 360.0 target_lons = target_lons.flatten() target_lats = target_lats.flatten() diff --git a/shakyground2/workflows.py b/shakyground2/workflows.py index b615026..ac0b5ae 100644 --- a/shakyground2/workflows.py +++ b/shakyground2/workflows.py @@ -116,6 +116,7 @@ def shakemaps_from_quakeml( ) results.num_sites = len(site_model) results.bbox_properties = site_model.bbox_properties + results.bbox_properties["cross_antimeridian"] = site_model.cross_antimeridian # Get the ground motion models results.tectonic_region, results.ground_motion_models = regionalization(results.earthquake) shakemap_config = {} @@ -127,6 +128,7 @@ def shakemaps_from_quakeml( "synthetic_rupture_site_spacing", ]: shakemap_config[key] = config.get(key, DEFAULT_CONFIGURATION[key]) + print(site_model) # Run the shakemap shakemap = Shakemap( results.earthquake, diff --git a/tests/data/gfz2021jqav.xml b/tests/data/gfz2021jqav.xml new file mode 100644 index 0000000..68ea92a --- /dev/null +++ b/tests/data/gfz2021jqav.xml @@ -0,0 +1 @@ +Rat Islands, Aleutian Islandsregion nameGFZ2021-05-17T20:33:32.797114Z1.519124002e+171.150862387e+17-1.237443836e+178.658144886e+158.143546196e+162.588668599e+16-3.820056546e+160.81692278630.7658606440.234139356GFZ2021-05-18T06:05:05.574667Zsmi:org.gfz-potsdam.de/geofon/Origin/20210518060505.575388.858842smi:org.gfz-potsdam.de/geofon/Magnitude/20210518060505.57545.858843smi:org.gfz-potsdam.de/geofon/BP_60s-150ssmi:org.gfz-potsdam.de/geofon/GEOFON_standard73.3066743162.2365899188.23008096257.101886827.8152913393.35776884339.093618172.705782961.416483959e+17164.616824617.21868289-1.60429869e+1774.13134631.5661094861.878147311e+1683.762354420.1830772137GFZ2021-05-18T06:05:05.574667Zsmi:org.gfz-potsdam.de/geofon/Origin/20210518055932.117269.1236929179.4231111.91611528451.320301063.84954094923117922417270.8228094851160.013641490.358741762.49188995470.25522614manualGFZ2021-05-18T05:59:32.122727Z20429.89541374.8097424068.542488249.555588176.0296631horizontal uncertaintysmi:org.gfz-potsdam.de/geofon/LOCSATsmi:org.gfz-potsdam.de/geofon/iasp91confirmed4383.76235442GFZ2021-05-18T06:05:05.574667Z5.387728817Mwsmi:org.gfz-potsdam.de/geofon/MTsmi:org.gfz-potsdam.de/geofon/Origin/20210518055932.117269.1236929smi:org.gfz-potsdam.de/geofon/Magnitude/20210518060505.57545.858843smi:org.gfz-potsdam.de/geofon/FocalMechanism/20210518060505.575219.858841 diff --git a/tests/site_model_test.py b/tests/site_model_test.py index 9e7869d..30791f5 100644 --- a/tests/site_model_test.py +++ b/tests/site_model_test.py @@ -128,6 +128,52 @@ class SiteModelTestCase(unittest.TestCase): sm1.site_array[key], value, nsites, SITE_PROPERTIES[key] ) + def test_build_from_bbox_crossing_antimeridian(self): + # Check that a valid site model is built when the bbox crosses the antimeridian + sm1 = SiteModel.from_bbox([178.0, -30.0, -178.0, -28.0], 1.0, 1.0, 800) + self.assertEqual(len(sm1), 15) + self.assertTrue(sm1.cross_antimeridian) + lons = np.array( + [ + 178.0, + 179.0, + 180.0, + -179.0, + -178.0, + 178.0, + 179.0, + 180.0, + -179.0, + -178.0, + 178.0, + 179.0, + 180.0, + -179.0, + -178.0, + ] + ) + lats = np.array( + [ + -30.0, + -30.0, + -30.0, + -30.0, + -30.0, + -29.0, + -29.0, + -29.0, + -29.0, + -29.0, + -28.0, + -28.0, + -28.0, + -28.0, + -28.0, + ] + ) + np.testing.assert_array_almost_equal(sm1["lon"], lons) + np.testing.assert_array_almost_equal(sm1["lat"], lats) + def test_build_from_bbox_minimal(self): # Build the site model from a minimal set of inputs sm1 = SiteModel.from_bbox(self.bbox, self.spcx, self.spcy, self.vs30) diff --git a/tests/workflows_test.py b/tests/workflows_test.py index ecab8bc..4ee51ea 100644 --- a/tests/workflows_test.py +++ b/tests/workflows_test.py @@ -42,6 +42,18 @@ class GeofonWorkflowTestCase(unittest.TestCase): self.assertIsInstance(results.shakemaps[maptype][imt], bytes) self.assertIsInstance(results.contours["mean"][imt], GeoDataFrame) + def test_complete_workflow_crossing_antimeridian(self): + event_id = os.path.join(DATA_PATH, "gfz2021jqav.xml") + results = shakemaps_from_quakeml(event_id, self.imts, config={"spcx": 0.1, "spcy": 0.1}) + self.assertEqual(results.num_sites, 14841) + self.assertListEqual(list(results.shakemaps), ["mean", "stddevs"]) + self.assertListEqual(list(results.shakemaps["mean"]), self.imts) + self.assertIsInstance(results, ShakemapWorkflowResult) + for imt in self.imts: + for maptype in results.shakemaps: + self.assertIsInstance(results.shakemaps[maptype][imt], bytes) + self.assertIsInstance(results.contours["mean"][imt], GeoDataFrame) + def test_workflow_with_exports(self): test_folder = os.path.join(DATA_PATH, "tmp_shakemaps_from_quakeml") event_id = os.path.join(DATA_PATH, "gfz2021eksc.xml") -- GitLab From 96b7fceb368cdfcb4006df1cc609600e74d1dd4a Mon Sep 17 00:00:00 2001 From: g-weatherill Date: Fri, 28 May 2021 08:33:05 +0200 Subject: [PATCH 3/6] Removes unwanted print statement --- shakyground2/workflows.py | 1 - 1 file changed, 1 deletion(-) diff --git a/shakyground2/workflows.py b/shakyground2/workflows.py index ac0b5ae..2f9684a 100644 --- a/shakyground2/workflows.py +++ b/shakyground2/workflows.py @@ -128,7 +128,6 @@ def shakemaps_from_quakeml( "synthetic_rupture_site_spacing", ]: shakemap_config[key] = config.get(key, DEFAULT_CONFIGURATION[key]) - print(site_model) # Run the shakemap shakemap = Shakemap( results.earthquake, -- GitLab From e01bd727264ab6c4b2b1387bae699f9bcc7e0c00 Mon Sep 17 00:00:00 2001 From: g-weatherill Date: Mon, 31 May 2021 15:02:28 +0200 Subject: [PATCH 4/6] Improve handling of site array crossing antimeridian --- shakyground2/site_model.py | 21 ++++++++++++++++--- tests/site_model_test.py | 41 +++++++++++++++++++++++++++++++++++--- 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/shakyground2/site_model.py b/shakyground2/site_model.py index 8462915..43c44ca 100644 --- a/shakyground2/site_model.py +++ b/shakyground2/site_model.py @@ -55,7 +55,22 @@ class SiteModel(object): if "cross_antimeridian" in bbox_properties: self.cross_antimeridian = bbox_properties.pop("cross_antimeridian") else: - self.cross_antimeridian = False + bbox = [ + np.min(site_array["lon"]), + np.min(site_array["lat"]), + np.max(site_array["lon"]), + np.max(site_array["lat"]), + ] + if (bbox[2] - bbox[0]) > 180.0: + warnings.warn( + "Upper longitude of bounding box exceeds lower longitude " + "by more than 180.0. Assuming antimeridian crossing. If this is " + "not the case set `bbox_properties={'cross_antimeridian': False}" + " in the call to the invoking function" + ) + self.cross_antimeridian = True + else: + self.cross_antimeridian = False self.bbox_properties = bbox_properties def __len__(self): @@ -217,7 +232,7 @@ class SiteModel(object): return cls(site_array, bbox_properties=bbox_properties) @classmethod - def from_dataframe(cls, dframe: pd.DataFrame) -> SiteModel: + def from_dataframe(cls, dframe: pd.DataFrame, bbox_properties: Dict = {}) -> SiteModel: """ Builds the site collection directly from a pandas dataframe @@ -252,7 +267,7 @@ class SiteModel(object): site_array[key] = cls._get_boolean_array(nsites, value) else: site_array[key] = value * np.ones(nsites, dtype=SITE_PROPERTIES[key]) - return cls(site_array) + return cls(site_array, bbox_properties) @staticmethod def _get_string_array(num_elem: int, key: str, dtype) -> np.ndarray: diff --git a/tests/site_model_test.py b/tests/site_model_test.py index 30791f5..555d17d 100644 --- a/tests/site_model_test.py +++ b/tests/site_model_test.py @@ -4,6 +4,7 @@ Test suite for the site model class import unittest import warnings import numpy as np +import pandas as pd from openquake.hazardlib.geo import Point from openquake.hazardlib.site import Site, SiteCollection from shakyground2.site_model import SiteModel, SITE_PROPERTIES @@ -20,16 +21,21 @@ class SiteModelTestCase(unittest.TestCase): def test_length(self): dummy_array = np.zeros([20, 10]) - sc1 = SiteModel(dummy_array) + sc1 = SiteModel(dummy_array, bbox_properties={"cross_antimeridian": False}) self.assertEqual(len(sc1), 20) def test_string(self): # No bounding box case dummy_array = np.zeros([20, 10]) - sc1 = SiteModel(dummy_array) + sc1 = SiteModel(dummy_array, bbox_properties={"cross_antimeridian": False}) self.assertEqual(str(sc1), "SiteModel(20 sites)") # Bounding box case - bbox_properties = {"bbox": [1.0, 2.0, 3.0, 4.0], "spcx": 0.5, "spcy": 0.5} + bbox_properties = { + "bbox": [1.0, 2.0, 3.0, 4.0], + "spcx": 0.5, + "spcy": 0.5, + "cross_antimeridian": False, + } sc1 = SiteModel(dummy_array, bbox_properties) self.assertEqual( str(sc1), @@ -174,6 +180,35 @@ class SiteModelTestCase(unittest.TestCase): np.testing.assert_array_almost_equal(sm1["lon"], lons) np.testing.assert_array_almost_equal(sm1["lat"], lats) + def test_build_from_dataframe_crossing_antimeridian(self): + # Test case for building site model from a dataframe with sites + # crossing the antimeridian + lons, lats = np.meshgrid(np.arange(178.0, 182.5, 0.5), np.arange(-30.0, -25.0, 0.5)) + lons = lons.flatten() + lons[lons > 180.0] -= 360.0 + lats = lats.flatten() + sids = np.arange(1, len(lons) + 1) + vs30 = 800.0 * np.ones(len(lons)) + input_site_data = pd.DataFrame({"sids": sids, "lon": lons, "lat": lats, "vs30": vs30}) + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + sm1 = SiteModel.from_dataframe(input_site_data) + self.assertEqual( + str(w[-1].message), + "Upper longitude of bounding box exceeds lower longitude " + "by more than 180.0. Assuming antimeridian crossing. If this is " + "not the case set `bbox_properties={'cross_antimeridian': False}" + " in the call to the invoking function", + ) + self.assertTrue(sm1.cross_antimeridian) + + # Check the case when the crossing antimeridian check is over-ridden + sm2 = SiteModel.from_dataframe( + input_site_data, bbox_properties={"cross_antimeridian": False} + ) + self.assertFalse(sm2.cross_antimeridian) + self.assertEqual(len(sm1), len(sm2)) + def test_build_from_bbox_minimal(self): # Build the site model from a minimal set of inputs sm1 = SiteModel.from_bbox(self.bbox, self.spcx, self.spcy, self.vs30) -- GitLab From 3bcbb9d4a024312da5ce994ada993fb644d60e10 Mon Sep 17 00:00:00 2001 From: g-weatherill Date: Tue, 1 Jun 2021 15:52:14 +0200 Subject: [PATCH 5/6] Edits to site_model to address MR comments --- shakyground2/site_model.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/shakyground2/site_model.py b/shakyground2/site_model.py index 43c44ca..27717c7 100644 --- a/shakyground2/site_model.py +++ b/shakyground2/site_model.py @@ -45,12 +45,14 @@ class SiteModel(object): Attributes: site_array: Array of sites and their corresponding properties as numpy.ndarray bbox_properties: Properties of the bounding box used to create the site array - (where relevant) - cross_antimeridian: Indicates that the site model crosses the antimeridian (True) or - not (False) + (where relevant). Should contain "cross_antimeridian: True" if the + site model crosses the antimeridian, even if the site model is not + constructed from a bounding box. """ - def __init__(self, site_array: np.ndarray, bbox_properties: Dict = {}): + def __init__(self, site_array: np.ndarray, bbox_properties: Optional[Dict] = None): + if bbox_properties is None: + bbox_properties = {} self.site_array = site_array if "cross_antimeridian" in bbox_properties: self.cross_antimeridian = bbox_properties.pop("cross_antimeridian") @@ -232,7 +234,9 @@ class SiteModel(object): return cls(site_array, bbox_properties=bbox_properties) @classmethod - def from_dataframe(cls, dframe: pd.DataFrame, bbox_properties: Dict = {}) -> SiteModel: + def from_dataframe( + cls, dframe: pd.DataFrame, bbox_properties: Optional[Dict] = None + ) -> SiteModel: """ Builds the site collection directly from a pandas dataframe @@ -242,6 +246,8 @@ class SiteModel(object): Returns: Instance of :class`shakygroundv2.site_model.SiteModel` """ + if bbox_properties is None: + bbox_properties = {} nsites = dframe.shape[0] site_dtype = np.dtype(list(SITE_PROPERTIES.items())) site_array = np.zeros(nsites, site_dtype) -- GitLab From 1b5ca4ff9cb6bd095df9c6fbbb7c674a0200d50b Mon Sep 17 00:00:00 2001 From: g-weatherill Date: Wed, 2 Jun 2021 12:01:55 +0200 Subject: [PATCH 6/6] Revises description of cross_antimeridian in bbox_properties of site model --- shakyground2/site_model.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/shakyground2/site_model.py b/shakyground2/site_model.py index 27717c7..3249e2a 100644 --- a/shakyground2/site_model.py +++ b/shakyground2/site_model.py @@ -44,10 +44,12 @@ class SiteModel(object): Attributes: site_array: Array of sites and their corresponding properties as numpy.ndarray - bbox_properties: Properties of the bounding box used to create the site array - (where relevant). Should contain "cross_antimeridian: True" if the - site model crosses the antimeridian, even if the site model is not - constructed from a bounding box. + bbox_properties: Properties of the bounding box used to create the site array, if it + has been constructed from a bounding box. If the site model was not + constructed from a bounding box then "bbox_properties" is not needed + except if the site model spans more than one hemisphere without + crossing the meridian, in which case this should contain + "cross_antimeridian: False". """ def __init__(self, site_array: np.ndarray, bbox_properties: Optional[Dict] = None): -- GitLab