def attach_new_origin( old_event: Event, new_event: Event, new_origin: Origin, preferred: bool, index: Optional[int] = None, ) -> Catalog: """ Attach a new origin to an existing events object. Parameters ---------- old_event : obspy.core.event.Event The old event that will receive the new origin new_event : obspy.core.event.Event The new event that contains the origin, needed for merging picks that may not exist in old_event new_origin : obspy.core.event.Origin The new origin that will be attached to old_event preferred : bool If True mark the new origin as the preferred_origin index : int or None The origin index of old_cat that new_origin will overwrite, if None append the new_origin to old_cat.origins Returns ------- obspy.Catalog modifies old_cat in-place, returns old_catalog """ # make sure all the picks/amplitudes in new_event are also in old_event merge_events(old_event, new_event, delete_old=False) # point the arrivals in the new origin at the old picks _associate_picks(old_event, new_event, new_origin) # append the origin if index is not None: # if this origin is to replace another try: old_ori = old_event.origins[index] except IndexError: msg = ("%d is not valid for an origin list of length %d") % ( index, len(old_event.origins), ) msg += " appending new origin to end of list" warnings.warn(msg) old_event.origins.append(new_origin) else: # set resource id and creation info new_origin.resource_id = old_ori.resource_id new_origin.creation_info = old_ori.creation_info old_event.origins[index] = new_origin else: old_event.origins.append(new_origin) # bump origin creation info bump_creation_version(new_origin) # set preferred if preferred: old_event.preferred_origin_id = new_origin.resource_id validate_catalog(old_event) return old_event
def test_duplicate_objects_raise(self, cat1_multiple_resource_ids): """ Make sure an assertion error is raised on cat2 as it's resource ids are not unique. """ with pytest.raises(AssertionError): validate_catalog(cat1_multiple_resource_ids)
def test_reject_old(self, merge_catalogs_delete_pick): """ Test that when a pick is deleted from the new cat_name and the CATALOG_PATH are merged it is also rejected on the old. """ cat1, cat2 = merge_catalogs_delete_pick # Make sure both events are still valid validate_catalog(cat1) validate_catalog(cat2) def _check_vals(attr, val, hash_attr): assert len(cat1[0].picks) == len(cat2[0].picks) + 1 eve1_wids = _hash_wids(getattr(cat1[0], attr), hash_attr) eve2_wids = _hash_wids(getattr(cat1[0], attr), hash_attr) assert set(eve2_wids).issubset(set(eve1_wids)) for key, obj in eve1_wids.items(): if key in eve2_wids: assert getattr(obj, val) == getattr(eve2_wids[key], val) else: assert obj.evaluation_status == "rejected" # Check the picks _check_vals("picks", "time", "phase_hint") # Check the amplitudes _check_vals("amplitudes", "generic_amplitude", "magnitude_hint")
def test_duplicate_unknown_picks_ok(self, cat_duplicate_unknown_phase_hints): """ Picks that are unknown (have a "?" for the phase hint) shouldn't count as duplicated """ # this should not raise validate_catalog(cat_duplicate_unknown_phase_hints)
def test_amp_lims(self, cat1): """ensure raise if there are any above limit amplitudes picks""" cat = cat1.copy() # Assigning an amplitude an above limit value cat[0].amplitudes[0].generic_amplitude = 1 with pytest.raises(AssertionError): validate_catalog(cat, amp_lim=0.5)
def cat1_cleared_preferreds(self, cat1): """ clear the preferred values of the events, return events """ validate_catalog(cat1) cat = cat1.copy() cat[0].preferred_origin_id = None cat[0].preferred_magnitude_id = None cat[0].preferred_focal_mechanism_id = None return cat
def insert_origin_catalog(self, origin_pack): """ insert the origin to overwrite old origin """ cat1, cat2, origin = origin_pack # ensure origin is a modified version of cat2's first origin self.ensure_common_arrivals(origin, cat2[0].origins[0]) attach_new_origin(cat1[0], cat2[0], origin, preferred=True, index=0) validate_catalog(cat1) return cat1
def test_z_amps(self, cat1): """Raise if there are any amplitude picks on Z axis""" cat = cat1.copy() # Assigning iaml pick to a z channel # picks[23] is a known iaml pick cat[0].picks[23].waveform_id.channel_code = "HHZ" with pytest.raises(AssertionError): validate_catalog(cat, no_z_amps=True)
def test_p_lims(self, cat1): """ensure raise if there are any outlying P picks""" cat = cat1.copy() # Assigning p pick an outlying time (1 hour off) # picks[2] is a known p pick cat[0].picks[2].time = cat[0].picks[2].time + 60 * 60 with pytest.raises(AssertionError): validate_catalog(cat, p_lim=30 * 60)
def test_pick_times(self, merged_catalogs): """ test that the times are the same in the picks """ cat1, cat2 = merged_catalogs assert len(cat1[0].picks) == len(cat2[0].picks) for pick1, pick2 in zip(cat1[0].picks, cat2[0].picks): assert pick1.time == pick2.time assert pick1.resource_id != pick2.resource_id validate_catalog(cat1) validate_catalog(cat2)
def extract_merge_catalogs(merge_directory): """ given a directory with two qmls, read in the qmls and return """ files = glob(join(merge_directory, "*")) cat_path1 = [x for x in files if x.endswith("1.xml")] cat_path2 = [x for x in files if x.endswith("2.xml")] cat1 = obspy.read_events(cat_path1[0]) cat2 = obspy.read_events(cat_path2[0]) validate_catalog(cat1) validate_catalog(cat2) return cat1.copy(), cat2.copy()
def test_amp_filts(self, cat1): """ensure raise if unexpected filter used""" cat = cat1.copy() amp = cat[0].amplitudes[0] # Assigning bad filter to an amplitude good_filt = "smi:local/Wood_Anderson_Simulation" bad_filt = "smi:local/Sean_Anderson_Simulation" rid = ResourceIdentifier(bad_filt, referred_object=amp) amp.filter_id = rid with pytest.raises(AssertionError): validate_catalog(cat, filter_ids=good_filt)
def test_iaml_before_p(self, cat1): """ ensure raise if there are any iaml picks that are before p picks """ cat = cat1.copy() # Moving a iaml time before p time on the same station # picks[23] is a known iaml pick # picks[2] is a known p pick cat[0].picks[23].time = cat[0].picks[2].time - 60 with pytest.raises(AssertionError): validate_catalog(cat)
def test_add_pick(self, merge_catalogs_add_pick): """ test that when a pick is added to the new cat_name it shows up in the old cat_name """ cat1, cat2 = merge_catalogs_add_pick assert len(cat1[0].picks) == len(cat2[0].picks) for pick1, pick2 in zip(cat1[0].picks, cat2[0].picks): assert pick1.time == pick2.time assert len(cat1[0].amplitudes) == len(cat2[0].amplitudes) for amp1, amp2 in zip(cat1[0].amplitudes, cat2[0].amplitudes): assert amp1.generic_amplitude == amp2.generic_amplitude validate_catalog(cat1) validate_catalog(cat2)
def test_amp_times(self, cat1): """ ensure raise if there are any amplitude times that don't match it's referred pick time """ cat = cat1.copy() # Assigning bad time window to an amplitude pick = cat[0].amplitudes[0].pick_id.get_referred_object() tw = TimeWindow(begin=0, end=0.5, reference=pick.time + 10) cat[0].amplitudes[0].time_window = tw with pytest.raises(AssertionError): validate_catalog(cat)
def test_pcat1_cleared_preferreds(self, cat1_cleared_preferreds): """ cleared preferreds should be reset to last in list""" cat = cat1_cleared_preferreds validate_catalog(cat) self.preferreds_are_set(cat) # make sure it is the last ones in the list ev = cat[0] if len(ev.origins): assert ev.preferred_origin() == ev.origins[-1] if len(ev.magnitudes): assert ev.preferred_magnitude() == ev.magnitudes[-1] if len(cat[0].focal_mechanisms): assert ev.preferred_focal_mechanism() == ev.focal_mechanisms[-1]
def test_cat1_preferred_cache_empty(self, cat1_preferred_cache_empty): """ ensure preferred still point to correct (not last) origins/mags """ cat = cat1_preferred_cache_empty validate_catalog(cat) self.preferreds_are_set(cat) # ensure the preferred are still the first if len(cat[0].origins): first_origin = cat[0].origins[0] assert cat[0].preferred_origin() == first_origin if len(cat[0].magnitudes): first_magnitude = cat[0].magnitudes[0] assert cat[0].preferred_magnitude() == first_magnitude if len(cat[0].focal_mechanisms): first_mech = cat[0].focal_mechanisms[0] assert cat[0].preferred_focal_mechanism() == first_mech
def test_duplicate_station_different_network(self, cat1): """ Ensure picks can have duplicated station codes if they have different network codes. See issue #173. """ # Add a copy of first pick, add new resource id and a new network code new_pick1 = copy.deepcopy(cat1[0].picks[0]) new_pick1.waveform_id.network_code = "NW" new_pick1.resource_id = ev.ResourceIdentifier() cat1[0].picks.append(new_pick1) # Do the same for network codes new_pick2 = copy.deepcopy(cat1[0].picks[0]) new_pick2.waveform_id.location_code = "04" new_pick2.resource_id = ev.ResourceIdentifier() # test passes if this doesnt raise validate_catalog(cat1)
def test_duplicate_picks_ok_if_rejected(self, cat1): """ Rejected picks should not count against duplicated """ cat = cat1.copy() # get first non-rejected pick for pick in cat1[0].picks: if pick.evaluation_status != "rejected": pick = pick.copy() break else: raise ValueError("all picks rejected") pick.resource_id = obspy.core.event.ResourceIdentifier( referred_object=pick) pick.evaluation_status = "rejected" cat[0].picks.append(pick) # this should not raise validate_catalog(cat)
def merge_catalogs_delete_pick(self, qml_to_merge_basic): """ Delete a pick and amplitude from the new cat, merge with old.""" cat1, cat2 = extract_merge_catalogs(qml_to_merge_basic) # Get rid of the first arrival and its associated pick arrivals = cat2[0].preferred_origin().arrivals pick_id = arrivals[0].pick_id assert not pick_id.get_referred_object( ).evaluation_status == "rejected" cat2[0].picks = [ x for x in cat2[0].picks if not x.resource_id == pick_id ] arrivals.pop(0) # Get rid of the first amplitude cat2[0].amplitudes.pop(0) validate_catalog(cat1) validate_catalog(cat2) merge_events(cat1[0], cat2[0]) return cat1, cat2
def origin_pack(self, merge_catalogs_function): """ using the second events from the merge set, create an origin object that will be attached to the first events """ cat1 = merge_catalogs_function[0].copy() cat2 = merge_catalogs_function[1].copy() validate_catalog(cat2) origin = cat2[0].preferred_origin() or cat2[0].origins[-1] origin.time += 1.0 origin.latitude *= 1.05 origin.longitude *= 1.05 rid = obspy.core.event.ResourceIdentifier() rid.set_referred_object(origin) origin.resource_id = rid # ensure all picks are accounted for on second events origin_pick_id = {x.pick_id.id for x in origin.arrivals} pick_ids = {x.resource_id.id for x in cat2[0].picks} assert origin_pick_id.issubset(pick_ids) return cat1, cat2, origin
def test_insert_origin_out_of_bounds(self, origin_pack): """ ensure the origin is still found even if bogus index was used """ cat1, cat2, origin = origin_pack # ensure origin is a modified version of cat2's first origin self.ensure_common_arrivals(origin, cat2[0].origins[0]) with pytest.warns(UserWarning) as w: attach_new_origin(cat1[0], cat2[0], origin, preferred=True, index=500) assert len(w) != 0 validate_catalog(cat1) self.origin_is_preferred(cat1, origin) assert origin in cat1[0].origins assert cat1[0].origins[-1] == origin
def val_cat(self, cat1, add_validator): """ validate the events exactly once, return result """ return validate_catalog(cat1)
def test_bad_arrival_pick_id_raises(self, cat1_bad_arrival_pick_id): """ make sure a bad pick_id in arrivals raises assertion error """ with pytest.raises(AssertionError): validate_catalog(cat1_bad_arrival_pick_id)
def cat1(event_cache): """ return a copy of events 1""" cat = event_cache["2017-01-16T01-15-13-8a42f.xml"].copy() validate_catalog(cat) cat[0].focal_mechanisms.append(obspy.core.event.FocalMechanism()) return cat
def test_works_with_event(self, cat1): """ ensure the method can also be called on an event """ validate_catalog(cat1[0])
def test_none_in_arrival_pick_id_fails(self, cat1_none_arrival_pick_id): """ make sure if an arrival has a None pick validate raises """ with pytest.raises(AssertionError): validate_catalog(cat1_none_arrival_pick_id)
def cat_nullish_nslc_codes(self, cat1): """ Create several picks with nullish location codes. """ cat1[0].picks[0].waveform_id.location_code = "--" cat1[0].picks[1].waveform_id.location_code = None return validate_catalog(cat1)
def test_empty_phase_hint_raises(self, cat1_no_pick_phase_hints): """ ensure raises if any phase hints are undefined """ with pytest.raises(AssertionError): validate_catalog(cat1_no_pick_phase_hints)
def test_empty_pick_wid_raises(self, cat1_no_pick_waveform_id): """ ensure raise if any waveform ids are empty on picks """ with pytest.raises(AssertionError): validate_catalog(cat1_no_pick_waveform_id)