1# http://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
5from __future__ import absolute_import
6import logging
7from pyrocko.guts import StringPattern, StringChoice, String, Float, Int,\
8 Timestamp, Object, List, Union, Bool, Unicode
9from pyrocko.model import event
10from pyrocko.gui import marker
11from pyrocko import moment_tensor
12import numpy as num
14logger = logging.getLogger('pyrocko.io.quakeml')
16guts_prefix = 'quakeml'
17guts_xmlns = 'http://quakeml.org/xmlns/bed/1.2'
18polarity_choices = {'positive': 1, 'negative': -1, 'undecidable': None}
21class QuakeMLError(Exception):
22 pass
25class NoPreferredOriginSet(QuakeMLError):
26 pass
29def one_element_or_none(li):
30 if len(li) == 1:
31 return li[0]
32 elif len(li) == 0:
33 return None
34 else:
35 logger.warning('More than one element in list: {}'.format(li))
36 return None
39class ResourceIdentifier(StringPattern):
40 pattern = "^(smi|quakeml):[\\w\\d][\\w\\d\\-\\.\\*\\(\\)_~']{2,}/[\\w" +\
41 "\\d\\-\\.\\*\\(\\)_~'][\\w\\d\\-\\.\\*\\(\\)\\+\\?_~'=,;#/&]*$"
44class WhitespaceOrEmptyStringType(StringPattern):
45 pattern = '^\\s*$'
48class OriginUncertaintyDescription(StringChoice):
49 choices = [
50 'horizontal uncertainty',
51 'uncertainty ellipse',
52 'confidence ellipsoid']
55class AmplitudeCategory(StringChoice):
56 choices = ['point', 'mean', 'duration', 'period', 'integral', 'other']
59class OriginDepthType(StringChoice):
60 choices = [
61 'from location',
62 'from moment tensor inversion',
63 'from modeling of broad-band P waveforms',
64 'constrained by depth phases',
65 'constrained by direct phases',
66 'constrained by depth and direct phases',
67 'operator assigned',
68 'other']
71class OriginType(StringChoice):
72 choices = [
73 'hypocenter',
74 'centroid',
75 'amplitude',
76 'macroseismic',
77 'rupture start',
78 'rupture end']
81class MTInversionType(StringChoice):
82 choices = ['general', 'zero trace', 'double couple']
85class EvaluationMode(StringChoice):
86 choices = ['manual', 'automatic']
89class EvaluationStatus(StringChoice):
90 choices = ['preliminary', 'confirmed', 'reviewed', 'final', 'rejected']
93class PickOnset(StringChoice):
94 choices = ['emergent', 'impulsive', 'questionable']
97class EventType(StringChoice):
98 choices = [
99 'not existing',
100 'not reported',
101 'earthquake',
102 'anthropogenic event',
103 'collapse',
104 'cavity collapse',
105 'mine collapse',
106 'building collapse',
107 'explosion',
108 'accidental explosion',
109 'chemical explosion',
110 'controlled explosion',
111 'experimental explosion',
112 'industrial explosion',
113 'mining explosion',
114 'quarry blast',
115 'road cut',
116 'blasting levee',
117 'nuclear explosion',
118 'induced or triggered event',
119 'rock burst',
120 'reservoir loading',
121 'fluid injection',
122 'fluid extraction',
123 'crash',
124 'plane crash',
125 'train crash',
126 'boat crash',
127 'other event',
128 'atmospheric event',
129 'sonic boom',
130 'sonic blast',
131 'acoustic noise',
132 'thunder',
133 'avalanche',
134 'snow avalanche',
135 'debris avalanche',
136 'hydroacoustic event',
137 'ice quake',
138 'slide',
139 'landslide',
140 'rockslide',
141 'meteorite',
142 'volcanic eruption',
143 'duplicate earthquake',
144 'rockburst']
147class DataUsedWaveType(StringChoice):
148 choices = [
149 'P waves',
150 'body waves',
151 'surface waves',
152 'mantle waves',
153 'combined',
154 'unknown']
157class AmplitudeUnit(StringChoice):
158 choices = ['m', 's', 'm/s', 'm/(s*s)', 'm*s', 'dimensionless', 'other']
161class EventDescriptionType(StringChoice):
162 choices = [
163 'felt report',
164 'Flinn-Engdahl region',
165 'local time',
166 'tectonic summary',
167 'nearest cities',
168 'earthquake name',
169 'region name']
172class MomentTensorCategory(StringChoice):
173 choices = ['teleseismic', 'regional']
176class EventTypeCertainty(StringChoice):
177 choices = ['known', 'suspected']
180class SourceTimeFunctionType(StringChoice):
181 choices = ['box car', 'triangle', 'trapezoid', 'unknown']
184class PickPolarity(StringChoice):
185 choices = list(polarity_choices.keys())
188class AgencyID(String):
189 pass
192class Author(Unicode):
193 pass
196class Version(String):
197 pass
200class Phase(Object):
201 value = String.T(xmlstyle='content')
204class GroundTruthLevel(String):
205 pass
208class AnonymousNetworkCode(String):
209 pass
212class AnonymousStationCode(String):
213 pass
216class AnonymousChannelCode(String):
217 pass
220class AnonymousLocationCode(String):
221 pass
224class Type(String):
225 pass
228class MagnitudeHint(String):
229 pass
232class Region(Unicode):
233 pass
236class RealQuantity(Object):
237 value = Float.T()
238 uncertainty = Float.T(optional=True)
239 lower_uncertainty = Float.T(optional=True)
240 upper_uncertainty = Float.T(optional=True)
241 confidence_level = Float.T(optional=True)
244class IntegerQuantity(Object):
245 value = Int.T()
246 uncertainty = Int.T(optional=True)
247 lower_uncertainty = Int.T(optional=True)
248 upper_uncertainty = Int.T(optional=True)
249 confidence_level = Float.T(optional=True)
252class ConfidenceEllipsoid(Object):
253 semi_major_axis_length = Float.T()
254 semi_minor_axis_length = Float.T()
255 semi_intermediate_axis_length = Float.T()
256 major_axis_plunge = Float.T()
257 major_axis_azimuth = Float.T()
258 major_axis_rotation = Float.T()
261class TimeQuantity(Object):
262 value = Timestamp.T()
263 uncertainty = Float.T(optional=True)
264 lower_uncertainty = Float.T(optional=True)
265 upper_uncertainty = Float.T(optional=True)
266 confidence_level = Float.T(optional=True)
269class TimeWindow(Object):
270 begin = Float.T()
271 end = Float.T()
272 reference = Timestamp.T()
275class ResourceReference(ResourceIdentifier):
276 pass
279class DataUsed(Object):
280 wave_type = DataUsedWaveType.T()
281 station_count = Int.T(optional=True)
282 component_count = Int.T(optional=True)
283 shortest_period = Float.T(optional=True)
284 longest_period = Float.T(optional=True)
287class EventDescription(Object):
288 text = Unicode.T()
289 type = EventDescriptionType.T(optional=True)
292class SourceTimeFunction(Object):
293 type = SourceTimeFunctionType.T()
294 duration = Float.T()
295 rise_time = Float.T(optional=True)
296 decay_time = Float.T(optional=True)
299class OriginQuality(Object):
300 associated_phase_count = Int.T(optional=True)
301 used_phase_count = Int.T(optional=True)
302 associated_station_count = Int.T(optional=True)
303 used_station_count = Int.T(optional=True)
304 depth_phase_count = Int.T(optional=True)
305 standard_error = Float.T(optional=True)
306 azimuthal_gap = Float.T(optional=True)
307 secondary_azimuthal_gap = Float.T(optional=True)
308 ground_truth_level = GroundTruthLevel.T(optional=True)
309 maximum_distance = Float.T(optional=True)
310 minimum_distance = Float.T(optional=True)
311 median_distance = Float.T(optional=True)
314class Axis(Object):
315 azimuth = RealQuantity.T()
316 plunge = RealQuantity.T()
317 length = RealQuantity.T()
320class Tensor(Object):
321 mrr = RealQuantity.T(xmltagname='Mrr')
322 mtt = RealQuantity.T(xmltagname='Mtt')
323 mpp = RealQuantity.T(xmltagname='Mpp')
324 mrt = RealQuantity.T(xmltagname='Mrt')
325 mrp = RealQuantity.T(xmltagname='Mrp')
326 mtp = RealQuantity.T(xmltagname='Mtp')
329class NodalPlane(Object):
330 strike = RealQuantity.T()
331 dip = RealQuantity.T()
332 rake = RealQuantity.T()
335class CompositeTime(Object):
336 year = IntegerQuantity.T(optional=True)
337 month = IntegerQuantity.T(optional=True)
338 day = IntegerQuantity.T(optional=True)
339 hour = IntegerQuantity.T(optional=True)
340 minute = IntegerQuantity.T(optional=True)
341 second = RealQuantity.T(optional=True)
344class OriginUncertainty(Object):
345 horizontal_uncertainty = Float.T(optional=True)
346 min_horizontal_uncertainty = Float.T(optional=True)
347 max_horizontal_uncertainty = Float.T(optional=True)
348 azimuth_max_horizontal_uncertainty = Float.T(optional=True)
349 confidence_ellipsoid = ConfidenceEllipsoid.T(optional=True)
350 preferred_description = OriginUncertaintyDescription.T(optional=True)
351 confidence_level = Float.T(optional=True)
354class ResourceReferenceOptional(Union):
355 members = [ResourceReference.T(), WhitespaceOrEmptyStringType.T()]
358class CreationInfo(Object):
359 agency_id = AgencyID.T(optional=True, xmltagname='agencyID')
360 agency_uri = ResourceReference.T(optional=True, xmltagname='agencyURI')
361 author = Author.T(optional=True)
362 author_uri = ResourceReference.T(optional=True, xmltagname='authorURI')
363 creation_time = Timestamp.T(optional=True)
364 version = Version.T(optional=True)
367class StationMagnitudeContribution(Object):
368 station_magnitude_id = ResourceReference.T(xmltagname='stationMagnitudeID')
369 residual = Float.T(optional=True)
370 weight = Float.T(optional=True)
373class PrincipalAxes(Object):
374 t_axis = Axis.T()
375 p_axis = Axis.T()
376 n_axis = Axis.T(optional=True)
379class NodalPlanes(Object):
380 preferred_plane = Int.T(optional=True, xmlstyle='attribute')
381 nodal_plane1 = NodalPlane.T(optional=True)
382 nodal_plane2 = NodalPlane.T(optional=True)
385class WaveformStreamID(Object):
386 value = ResourceReferenceOptional.T(xmlstyle='content')
387 network_code = AnonymousNetworkCode.T(xmlstyle='attribute')
388 station_code = AnonymousStationCode.T(xmlstyle='attribute')
389 channel_code = AnonymousChannelCode.T(optional=True, xmlstyle='attribute')
390 location_code = AnonymousLocationCode.T(
391 optional=True, xmlstyle='attribute')
393 @property
394 def nslc_id(self):
395 return (self.network_code, self.station_code, self.location_code,
396 self.channel_code)
399class Comment(Object):
400 id = ResourceReference.T(optional=True, xmlstyle='attribute')
401 text = Unicode.T()
402 creation_info = CreationInfo.T(optional=True)
405class MomentTensor(Object):
406 public_id = ResourceReference.T(
407 xmlstyle='attribute', xmltagname='publicID')
408 data_used_list = List.T(DataUsed.T())
409 comment_list = List.T(Comment.T())
410 derived_origin_id = ResourceReference.T(
411 optional=True, xmltagname='derivedOriginID')
412 moment_magnitude_id = ResourceReference.T(
413 optional=True, xmltagname='momentMagnitudeID')
414 scalar_moment = RealQuantity.T(optional=True)
415 tensor = Tensor.T(optional=True)
416 variance = Float.T(optional=True)
417 variance_reduction = Float.T(optional=True)
418 double_couple = Float.T(optional=True)
419 clvd = Float.T(optional=True)
420 iso = Float.T(optional=True)
421 greens_function_id = ResourceReference.T(
422 optional=True, xmltagname='greensFunctionID')
423 filter_id = ResourceReference.T(optional=True, xmltagname='filterID')
424 source_time_function = SourceTimeFunction.T(optional=True)
425 method_id = ResourceReference.T(optional=True, xmltagname='methodID')
426 category = MomentTensorCategory.T(optional=True)
427 inversion_type = MTInversionType.T(optional=True)
428 creation_info = CreationInfo.T(optional=True)
430 def pyrocko_moment_tensor(self):
431 mrr = self.tensor.mrr.value
432 mtt = self.tensor.mtt.value
433 mpp = self.tensor.mpp.value
434 mrt = self.tensor.mrt.value
435 mrp = self.tensor.mrp.value
436 mtp = self.tensor.mtp.value
437 mt = moment_tensor.MomentTensor(m_up_south_east=num.matrix([
438 [mrr, mrt, mrp], [mrt, mtt, mtp], [mrp, mtp, mpp]]))
440 return mt
443class Amplitude(Object):
444 public_id = ResourceReference.T(
445 xmlstyle='attribute', xmltagname='publicID')
446 comment_list = List.T(Comment.T())
447 generic_amplitude = RealQuantity.T()
448 type = Type.T(optional=True)
449 category = AmplitudeCategory.T(optional=True)
450 unit = AmplitudeUnit.T(optional=True)
451 method_id = ResourceReference.T(optional=True, xmltagname='methodID')
452 period = RealQuantity.T(optional=True)
453 snr = Float.T(optional=True)
454 time_window = TimeWindow.T(optional=True)
455 pick_id = ResourceReference.T(optional=True, xmltagname='pickID')
456 waveform_id = WaveformStreamID.T(optional=True, xmltagname='waveformID')
457 filter_id = ResourceReference.T(optional=True, xmltagname='filterID')
458 scaling_time = TimeQuantity.T(optional=True)
459 magnitude_hint = MagnitudeHint.T(optional=True)
460 evaluation_mode = EvaluationMode.T(optional=True)
461 evaluation_status = EvaluationStatus.T(optional=True)
462 creation_info = CreationInfo.T(optional=True)
465class Magnitude(Object):
466 public_id = ResourceReference.T(
467 xmlstyle='attribute', xmltagname='publicID')
468 comment_list = List.T(Comment.T())
469 station_magnitude_contribution_list = List.T(
470 StationMagnitudeContribution.T())
471 mag = RealQuantity.T()
472 type = Type.T(optional=True)
473 origin_id = ResourceReference.T(optional=True, xmltagname='originID')
474 method_id = ResourceReference.T(optional=True, xmltagname='methodID')
475 station_count = Int.T(optional=True)
476 azimuthal_gap = Float.T(optional=True)
477 evaluation_mode = EvaluationMode.T(optional=True)
478 evaluation_status = EvaluationStatus.T(optional=True)
479 creation_info = CreationInfo.T(optional=True)
482class StationMagnitude(Object):
483 public_id = ResourceReference.T(
484 xmlstyle='attribute', xmltagname='publicID')
485 comment_list = List.T(Comment.T())
486 origin_id = ResourceReference.T(optional=True, xmltagname='originID')
487 mag = RealQuantity.T()
488 type = Type.T(optional=True)
489 amplitude_id = ResourceReference.T(optional=True, xmltagname='amplitudeID')
490 method_id = ResourceReference.T(optional=True, xmltagname='methodID')
491 waveform_id = WaveformStreamID.T(optional=True, xmltagname='waveformID')
492 creation_info = CreationInfo.T(optional=True)
495class Arrival(Object):
496 public_id = ResourceReference.T(
497 xmlstyle='attribute', xmltagname='publicID')
498 comment_list = List.T(Comment.T())
499 pick_id = ResourceReference.T(xmltagname='pickID')
500 phase = Phase.T()
501 time_correction = Float.T(optional=True)
502 azimuth = Float.T(optional=True)
503 distance = Float.T(optional=True)
504 takeoff_angle = RealQuantity.T(optional=True)
505 time_residual = Float.T(optional=True)
506 horizontal_slowness_residual = Float.T(optional=True)
507 backazimuth_residual = Float.T(optional=True)
508 time_weight = Float.T(optional=True)
509 time_used = Int.T(optional=True)
510 horizontal_slowness_weight = Float.T(optional=True)
511 backazimuth_weight = Float.T(optional=True)
512 earth_model_id = ResourceReference.T(
513 optional=True, xmltagname='earthModelID')
514 creation_info = CreationInfo.T(optional=True)
517class Pick(Object):
518 public_id = ResourceReference.T(
519 xmlstyle='attribute', xmltagname='publicID')
520 comment_list = List.T(Comment.T())
521 time = TimeQuantity.T()
522 waveform_id = WaveformStreamID.T(xmltagname='waveformID')
523 filter_id = ResourceReference.T(optional=True, xmltagname='filterID')
524 method_id = ResourceReference.T(optional=True, xmltagname='methodID')
525 horizontal_slowness = RealQuantity.T(optional=True)
526 backazimuth = RealQuantity.T(optional=True)
527 slowness_method_id = ResourceReference.T(
528 optional=True, xmltagname='slownessMethodID')
529 onset = PickOnset.T(optional=True)
530 phase_hint = Phase.T(optional=True)
531 polarity = PickPolarity.T(optional=True)
532 evaluation_mode = EvaluationMode.T(optional=True)
533 evaluation_status = EvaluationStatus.T(optional=True)
534 creation_info = CreationInfo.T(optional=True)
536 @property
537 def pyrocko_polarity(self):
538 return polarity_choices.get(self.polarity, None)
540 def get_pyrocko_phase_marker(self, event=None):
541 if not self.phase_hint:
542 logger.warn('Pick %s: phase_hint undefined' % self.public_id)
543 phasename = 'undefined'
544 else:
545 phasename = self.phase_hint.value
547 return marker.PhaseMarker(
548 event=event, nslc_ids=[self.waveform_id.nslc_id],
549 tmin=self.time.value, tmax=self.time.value,
550 phasename=phasename,
551 polarity=self.pyrocko_polarity,
552 automatic=self.evaluation_mode)
555class FocalMechanism(Object):
556 public_id = ResourceReference.T(
557 xmlstyle='attribute', xmltagname='publicID')
558 waveform_id_list = List.T(WaveformStreamID.T(xmltagname='waveformID'))
559 comment_list = List.T(Comment.T())
560 moment_tensor_list = List.T(MomentTensor.T())
561 triggering_origin_id = ResourceReference.T(
562 optional=True, xmltagname='triggeringOriginID')
563 nodal_planes = NodalPlanes.T(optional=True)
564 principal_axes = PrincipalAxes.T(optional=True)
565 azimuthal_gap = Float.T(optional=True)
566 station_polarity_count = Int.T(optional=True)
567 misfit = Float.T(optional=True)
568 station_distribution_ratio = Float.T(optional=True)
569 method_id = ResourceReference.T(optional=True, xmltagname='methodID')
570 evaluation_mode = EvaluationMode.T(optional=True)
571 evaluation_status = EvaluationStatus.T(optional=True)
572 creation_info = CreationInfo.T(optional=True)
575class Origin(Object):
576 public_id = ResourceReference.T(
577 xmlstyle='attribute', xmltagname='publicID')
578 composite_time_list = List.T(CompositeTime.T())
579 comment_list = List.T(Comment.T())
580 origin_uncertainty_list = List.T(OriginUncertainty.T())
581 arrival_list = List.T(Arrival.T())
582 time = TimeQuantity.T()
583 longitude = RealQuantity.T()
584 latitude = RealQuantity.T()
585 depth = RealQuantity.T(optional=True)
586 depth_type = OriginDepthType.T(optional=True)
587 time_fixed = Bool.T(optional=True)
588 epicenter_fixed = Bool.T(optional=True)
589 reference_system_id = ResourceReference.T(
590 optional=True, xmltagname='referenceSystemID')
591 method_id = ResourceReference.T(optional=True, xmltagname='methodID')
592 earth_model_id = ResourceReference.T(
593 optional=True, xmltagname='earthModelID')
594 quality = OriginQuality.T(optional=True)
595 type = OriginType.T(optional=True)
596 region = Region.T(optional=True)
597 evaluation_mode = EvaluationMode.T(optional=True)
598 evaluation_status = EvaluationStatus.T(optional=True)
599 creation_info = CreationInfo.T(optional=True)
601 def position_values(self):
602 lat = self.latitude.value
603 lon = self.longitude.value
604 if not self.depth:
605 logger.warn(
606 'Origin %s: Depth is undefined. Set to depth=0.' %
607 self.public_id)
608 depth = 0.
609 else:
610 depth = self.depth.value
612 return lat, lon, depth
614 def get_pyrocko_event(self):
615 lat, lon, depth = self.position_values()
616 otime = self.time.value
617 if self.creation_info:
618 cat = self.creation_info.agency_id
619 else:
620 cat = None
622 return event.Event(
623 name=self.public_id,
624 lat=lat,
625 lon=lon,
626 time=otime,
627 depth=depth,
628 catalog=cat,
629 region=self.region)
632class Event(Object):
633 public_id = ResourceReference.T(
634 xmlstyle='attribute', xmltagname='publicID')
635 description_list = List.T(EventDescription.T())
636 comment_list = List.T(Comment.T())
637 focal_mechanism_list = List.T(FocalMechanism.T())
638 amplitude_list = List.T(Amplitude.T())
639 magnitude_list = List.T(Magnitude.T())
640 station_magnitude_list = List.T(StationMagnitude.T())
641 origin_list = List.T(Origin.T())
642 pick_list = List.T(Pick.T())
643 preferred_origin_id = ResourceReference.T(
644 optional=True, xmltagname='preferredOriginID')
645 preferred_magnitude_id = ResourceReference.T(
646 optional=True, xmltagname='preferredMagnitudeID')
647 preferred_focal_mechanism_id = ResourceReference.T(
648 optional=True, xmltagname='preferredFocalMechanismID')
649 type = EventType.T(
650 optional=True)
651 type_certainty = EventTypeCertainty.T(
652 optional=True)
653 creation_info = CreationInfo.T(
654 optional=True)
655 region = Region.T(
656 optional=True)
658 def describe(self):
659 return '''%s:
660 origins: %i %s
661 magnitudes: %i %s
662 focal_machanisms: %i %s
663 picks: %i
664 amplitudes: %i
665 station_magnitudes: %i''' % (
666 self.public_id,
667 len(self.origin_list),
668 '@' if self.preferred_origin_id else '-',
669 len(self.magnitude_list),
670 '@' if self.preferred_magnitude_id else '-',
671 len(self.focal_mechanism_list),
672 '@' if self.preferred_focal_mechanism_id else '-',
673 len(self.pick_list),
674 len(self.amplitude_list),
675 len(self.station_magnitude_list))
677 def get_pyrocko_phase_markers(self):
678 event = self.get_pyrocko_event()
679 return [
680 p.get_pyrocko_phase_marker(event=event) for p in self.pick_list]
682 def get_pyrocko_event(self):
683 '''
684 Convert into Pyrocko event object.
686 Uses *preferred* origin, magnitude, and moment tensor. If no preferred
687 item is specified, it picks the first from the list and emits a
688 warning.
689 '''
691 origin = self.preferred_origin
692 if not origin and self.origin_list:
693 origin = self.origin_list[0]
694 if len(self.origin_list) > 1:
695 logger.warn(
696 'Event %s: No preferred origin set, '
697 'more than one available, using first' % self.public_id)
699 if not origin:
700 raise QuakeMLError(
701 'No origin available for event: %s' % self.public_id)
703 ev = origin.get_pyrocko_event()
705 foc_mech = self.preferred_focal_mechanism
706 if not foc_mech and self.focal_mechanism_list:
707 foc_mech = self.focal_mechanism_list[0]
708 if len(self.focal_mechanism_list) > 1:
709 logger.warn(
710 'Event %s: No preferred focal mechanism set, '
711 'more than one available, using first' % ev.name)
713 if foc_mech and foc_mech.moment_tensor_list:
714 ev.moment_tensor = \
715 foc_mech.moment_tensor_list[0].pyrocko_moment_tensor()
717 if len(foc_mech.moment_tensor_list) > 1:
718 logger.warn(
719 'more than one moment tensor available, using first')
721 mag = None
722 pref_mag = self.preferred_magnitude
723 if pref_mag:
724 mag = pref_mag
725 elif self.magnitude_list:
726 mag = self.magnitude_list[0]
727 if len(self.magnitude_list) > 1:
728 logger.warn(
729 'Event %s: No preferred magnitude set, '
730 'more than one available, using first' % ev.name)
732 if mag:
733 ev.magnitude = mag.mag.value
734 ev.magnitude_type = mag.type
736 ev.region = self.get_effective_region()
738 return ev
740 def get_effective_region(self):
741 if self.region:
742 return self.region
744 for desc in self.description_list:
745 if desc.type in ('Flinn-Engdahl region', 'region name'):
746 return desc.text
748 return None
750 @property
751 def preferred_origin(self):
752 return one_element_or_none(
753 [x for x in self.origin_list
754 if x.public_id == self.preferred_origin_id])
756 @property
757 def preferred_magnitude(self):
758 return one_element_or_none(
759 [x for x in self.magnitude_list
760 if x.public_id == self.preferred_magnitude_id])
762 @property
763 def preferred_focal_mechanism(self):
764 return one_element_or_none(
765 [x for x in self.focal_mechanism_list
766 if x.public_id == self.preferred_focal_mechanism_id])
769class EventParameters(Object):
770 public_id = ResourceReference.T(
771 xmlstyle='attribute', xmltagname='publicID')
772 comment_list = List.T(Comment.T())
773 event_list = List.T(Event.T(xmltagname='event'))
774 description = Unicode.T(optional=True)
775 creation_info = CreationInfo.T(optional=True)
778class QuakeML(Object):
779 '''
780 QuakeML data container.
781 '''
782 xmltagname = 'quakeml'
783 xmlns = 'http://quakeml.org/xmlns/quakeml/1.2'
784 guessable_xmlns = [xmlns, guts_xmlns]
786 event_parameters = EventParameters.T(optional=True)
788 def get_events(self):
789 return self.event_parameters.event_list
791 def get_pyrocko_events(self):
792 '''
793 Get event information in Pyrocko's basic event format.
795 :rtype:
796 List of :py:class:`pyrocko.model.event.Event` objects.
797 '''
798 events = []
799 for e in self.event_parameters.event_list:
800 events.append(e.get_pyrocko_event())
802 return events
804 def get_pyrocko_phase_markers(self):
805 '''
806 Get pick information in Pyrocko's basic marker format.
808 :rtype:
809 List of :py:class:`pyrocko.gui.marker.PhaseMarker` objects.
810 '''
811 markers = []
812 for e in self.event_parameters.event_list:
813 markers.extend(e.get_pyrocko_phase_markers())
815 return markers
817 @classmethod
818 def load_xml(cls, stream=None, filename=None, string=None):
819 '''
820 Load QuakeML data from stream, file or string.
822 :param stream:
823 Stream open for reading in binary mode.
824 :type stream:
825 file-like object, optional
827 :param filename:
828 Path to file to be opened for reading.
829 :type filename:
830 str, optional
832 :param string:
833 String with QuakeML data to be deserialized.
834 :type string:
835 str, optional
837 The arguments ``stream``, ``filename``, and ``string`` are mutually
838 exclusive.
840 :returns:
841 Parsed QuakeML data structure.
842 :rtype:
843 :py:class:`QuakeML` object
845 '''
847 return super(QuakeML, cls).load_xml(
848 stream=stream,
849 filename=filename,
850 string=string,
851 ns_hints=[
852 'http://quakeml.org/xmlns/quakeml/1.2',
853 'http://quakeml.org/xmlns/bed/1.2'],
854 ns_ignore=True)