Repository: obspy/obspy

Issue:
GSE2 bulletin reading: station magnitude contribution not created
I can see there is already a related/similar issue with this [(https://github.com/obspy/obspy/pull/2420 )] but since it has not been finalized I would create a new one.
I am not able to include stationMagnitude to the catalog conversion with my GSE2 format catalog. I thought it was because of my catalog. It might have some formatting problem but I tested it with the example file which was given in the documentation with the same result (no success). Basically, I am able to convert everything apart from the stationMagnitudes. I tested this with the latest v1.2.2 and v1.2.0 with the same result. > Any suggestion or any comment or help are highly appreciated.



Discussion:
Is it possible to openly share said problematic GS2 bulletin file? That'd be easiest for debugging.
Sure,

```
BEGIN GSE2.0
MSG_TYPE DATA
MSG_ID Example KAN
DATA_TYPE BULLETIN GSE2.0
Reviewed Event Bulletin (KAN) of the GSE_KAN for 2020.09.18
EVENT 20160101002419
   Date       Time       Latitude Longitude    Depth    Ndef Nsta Gap    Mag1  N    Mag2  N    Mag3  N  Author          ID
       rms   OT_Error      Smajor Sminor Az        Err   mdist  Mdist     Err        Err        Err     Quality

2016/01/01 00:24:19.6     39.9947   24.1035     29.7      22   16 224  ML 2.9 16                        KAN     0095371
      0.12                                         0.5    0.35   2.92                                   m i ke

AEGEAN SEA            
Sta    Dist   EvAz     Phase       Date      Time     TRes  Azim  AzRes  Slow  SRes Def  SNR        Amp   Per   Mag1   Mag2 Arr ID
OUR     0.35 344.0 m   P       2016/01/01 00:24:28.2   0.0                          T               2.7       ML 2.9         7448006
OUR     0.35 344.0 m   S       2016/01/01 00:24:34.5  -0.1                          T                                        4892011
GADA    1.39  82.0 m   P       2016/01/01 00:24:43.1  -0.4                          T               0.3       ML 2.6         6910611
BOZC    1.51  96.0 m   P       2016/01/01 00:24:44.9  -0.2                          T               0.4       ML 2.7         2403017
BOZC    1.51  96.0 m   S       2016/01/01 00:25:03.6  -0.2                          T                                        2380277
SIGR    1.56 120.0 m   P       2016/01/01 00:24:46.1   0.1                          T               0.2       ML 2.6         7670112
SIGR    1.56 120.0 m   S       2016/01/01 00:25:05.2   0.0                          T                                        8931514
EZN     1.72  96.0 m   P       2016/01/01 00:24:48.2   0.1                          T               0.2       ML 2.5         9234782
EZN     1.72  96.0 m   S       2016/01/01 00:25:08.9  -0.1                          T                                        8551473
ENEZ    1.73  65.0 m   P       2016/01/01 00:24:48.5   0.1                          T               0.8       ML 3.2         4474032
ENEZ    1.73  65.0 m   S       2016/01/01 00:25:09.3  -0.1                          T                                        2950612
ALN     1.74  59.0 m   P       2016/01/01 00:24:48.6   0.2                          T               0.1       ML 2.4         2776561
ALN     1.74  59.0 m   S       2016/01/01 00:25:09.6   0.1                          T                                        1118543
GELI    1.86  77.0 m   P       2016/01/01 00:24:50.3   0.1                          T               0.2       ML 2.8         7539174
ERIK    1.96  70.0 m   P       2016/01/01 00:24:51.7   0.1                          T               0.3       ML 3.0         6864222
LAP     2.07  80.0 m   P       2016/01/01 00:24:53.2   0.0                          T               0.4       ML 3.2         8574594
UKOP    2.23  60.0 m   P       2016/01/01 00:24:55.6   0.1                          T               0.2       ML 3.1         6583408
MAR3    2.55  73.0 m   P       2016/01/01 00:25:00.1   0.1                          T               0.4       ML 3.5         4378602
EDRB    2.73  47.0 m   P       2016/01/01 00:25:02.9   0.4                          T               0.1       ML 3.0         6007375
MRMT    2.73  77.0 m   P       2016/01/01 00:25:02.6   0.0                          T               0.1       ML 2.8         5163793
EDC     2.90  83.0 m   P       2016/01/01 00:25:04.9   0.0                          T               0.3       ML 3.4         5366164
BALB    2.92  97.0 m   P       2016/01/01 00:25:05.2   0.0                          T               0.1       ML 3.1         3144980


EVENT 20160101003726
   Date       Time       Latitude Longitude    Depth    Ndef Nsta Gap    Mag1  N    Mag2  N    Mag3  N  Author          ID
       rms   OT_Error      Smajor Sminor Az        Err   mdist  Mdist     Err        Err        Err     Quality

2016/01/01 00:37:26.5     39.1450   29.0460      6.9      10    7 105  ML 1.6  6                        KAN     0095372
      0.04                                         0.1    0.07   1.24                                   m i ke

WESTERN TURKEY        
Sta    Dist   EvAz     Phase       Date      Time     TRes  Azim  AzRes  Slow  SRes Def  SNR        Amp   Per   Mag1   Mag2 Arr ID
SMAA    0.07 229.0 m   P       2016/01/01 00:37:28.6   0.0                          T               0.6       ML 1.0         0073340
SMAA    0.07 229.0 m   S       2016/01/01 00:37:30.2   0.1                          T                                        1626669
SIMA    0.08 219.0 m   P       2016/01/01 00:37:28.8   0.0                          T               1.3       ML 1.5         1266595
SIMA    0.08 219.0 m   S       2016/01/01 00:37:30.4  -0.1                          T                                        0076946
SHAP    0.18 132.0 m   P       2016/01/01 00:37:30.7   0.0                          T               0.5       ML 1.6         4432130
SHAP    0.18 132.0 m   S       2016/01/01 00:37:33.8   0.0                          T                                        8150132
GEDZ    0.30 109.0 m   P       2016/01/01 00:37:32.9   0.0                          T               0.2       ML 1.6         0931392
TVSB    0.44  47.0 m   P       2016/01/01 00:37:35.5  -0.1                          T               0.1       ML 1.6         4683242
CAVI    1.22  30.0 m   P       2016/01/01 00:37:50.2   0.0                          T                                        7795269
KCTX    1.24 334.0 m   P       2016/01/01 00:37:50.6   0.0                          T               0.2       ML 2.2         4256956


EVENT 20160101012332
   Date       Time       Latitude Longitude    Depth    Ndef Nsta Gap    Mag1  N    Mag2  N    Mag3  N  Author          ID
       rms   OT_Error      Smajor Sminor Az        Err   mdist  Mdist     Err        Err        Err     Quality

2016/01/01 01:23:32.0     37.1188   28.7342      5.0       8    4 134  ML 1.9  4                        KAN     0095373
      0.18                                         0.3    0.36   1.30                                   m i ke

WESTERN TURKEY        
Sta    Dist   EvAz     Phase       Date      Time     TRes  Azim  AzRes  Slow  SRes Def  SNR        Amp   Per   Mag1   Mag2 Arr ID
YER     0.36 272.0 m   P       2016/01/01 01:23:40.4   0.1                          T               0.2       ML 1.8         5108745
YER     0.36 272.0 m   S       2016/01/01 01:23:46.5   0.1                          T                                        0490008
TURN    0.52 229.0 m   P       2016/01/01 01:23:43.0  -0.4                          T               0.1       ML 1.8         8882445
TURN    0.52 229.0 m   S       2016/01/01 01:23:51.8   0.1                          T                                        9323798
AYDB    1.06 321.0 m   P       2016/01/01 01:23:53.3  -0.3                          T               0.1       ML 2.1         5272017
AYDB    1.06 321.0 m   S       2016/01/01 01:24:09.4   0.1                          T                                        4212182
KORT    1.30  95.0 m   P       2016/01/01 01:23:58.0   0.1                          T               0.1       ML 2.1         4016066
KORT    1.30  95.0 m   S       2016/01/01 01:24:17.0   0.1                          T                                        5561642


EVENT 20160101013350
   Date       Time       Latitude Longitude    Depth    Ndef Nsta Gap    Mag1  N    Mag2  N    Mag3  N  Author          ID
       rms   OT_Error      Smajor Sminor Az        Err   mdist  Mdist     Err        Err        Err     Quality

2016/01/01 01:33:50.5     38.8322   37.8610     12.5       6    4 173  ML 1.6  4                        KAN     0095374
      0.09                                         0.2    0.39   1.22                                   m i ke

EASTERN TURKEY       
Sta    Dist   EvAz     Phase       Date      Time     TRes  Azim  AzRes  Slow  SRes Def  SNR        Amp   Per   Mag1   Mag2 Arr ID
DARE    0.39 229.0 m   P       2016/01/01 01:33:58.7   0.0                          T               0.1       ML 1.5         0674828
DARE    0.39 229.0 m   S       2016/01/01 01:34:04.9   0.0                          T                                        1351307
MALT    0.68 139.0 m   P       2016/01/01 01:34:04.3   0.2                          T               0.1       ML 1.9         7514566
MALT    0.68 139.0 m   S       2016/01/01 01:34:14.0  -0.1                          T                                        5884004
ILIC    0.83  42.0 m   P       2016/01/01 01:34:06.8  -0.1                          T               0.1       ML 1.8         0518587
SVRC    1.22 112.0 m   P       2016/01/01 01:34:14.1   0.2                          T               0.0       ML 1.4         2729437


STOP
```
@comoglu for me station magnitudes show up when i read that file

```python
In [1]: cat = read_events("cat.gse2")                                                                                                                  

In [2]: for event in cat: 
   ...:     print(len(event.station_magnitudes)) 
   ...:                                                                                                                                                
16
6
4
4

In [3]: for event in cat: 
   ...:     for magnitude in event.magnitudes: 
   ...:         print(len(magnitude.station_magnitude_contributions)) 
   ...:                                                                                                                                                
0
0
0
0
```

It seems that no "station magnitude contribution" objects are created and attached to the magnitude object. Was that what you were referring to?
Exactly, I have network Magnitude but no station magnitude object created for the individual station.
Uhm, like stated station magnitudes seem to be created, only thing thats not present is the link between station magnitudes and network magnitude, looks like to me?
Hmm, I just checked, You are right, I can see stationMagnitude with its publicID in SC3XML output. the only missing part is stationMagnitudeContribution link to each stationMagnitude, like below

```
<stationMagnitudeContribution>
          <stationMagnitudeID>StationMagnitude/20200928021740.070182.44922</stationMagnitudeID>
          <residual>0.02571178355</residual>
          <weight>1</weight>
</stationMagnitudeContribution>
```



Resolving patch:
diff --git a/obspy/io/gse2/bulletin.py b/obspy/io/gse2/bulletin.py
--- a/obspy/io/gse2/bulletin.py
+++ b/obspy/io/gse2/bulletin.py
@@ -21,7 +21,9 @@
                               CreationInfo, Event, EventDescription,
                               Magnitude, Origin, OriginQuality,
                               OriginUncertainty, Pick, ResourceIdentifier,
-                              StationMagnitude, WaveformStreamID)
+                              StationMagnitude,
+                              StationMagnitudeContribution,
+                              WaveformStreamID)
 from obspy.core.event.header import (
     EvaluationMode, EventDescriptionType, EventType, EventTypeCertainty,
     OriginDepthType, OriginUncertaintyDescription, PickOnset, PickPolarity)
@@ -616,6 +618,12 @@ def _parse_first_line_origin(self, line, event, magnitudes):
 
         return origin, origin_res_id
 
+    def _find_magnitude_by_type(self, event, origin_res_id, magnitude_type):
+        for mag in event.magnitudes:
+            if mag.origin_id == origin_res_id \
+                    and mag.magnitude_type == magnitude_type:
+                return mag
+
     def _parse_second_line_origin(self, line, event, origin, magnitudes):
         magnitude_errors = []
 
@@ -909,9 +917,19 @@ def _parse_arrivals(self, event, origin, origin_res_id):
                     sta_mag.amplitude_id = amplitude.resource_id
                     sta_mag.station_magnitude_type = magnitude_types[i]
                     sta_mag.mag = magnitude_values[i]
+                    sta_mag.waveform_id = pick.waveform_id
                     public_id = "magnitude/station/%s/%s" % (line_id, i)
                     sta_mag.resource_id = self._get_res_id(public_id)
                     event.station_magnitudes.append(sta_mag)
+
+                    # Associate station mag with network mag of same type
+                    mag = self._find_magnitude_by_type(event, origin_res_id,
+                                                       magnitude_types[i])
+                    if mag:
+                        contrib = StationMagnitudeContribution()
+                        contrib.station_magnitude_id = sta_mag.resource_id
+                        contrib.weight = 1.0
+                        mag.station_magnitude_contributions.append(contrib)
             except ValueError:
                 pass
 


Test patch:
diff --git a/obspy/io/gse2/tests/test_bulletin.py b/obspy/io/gse2/tests/test_bulletin.py
--- a/obspy/io/gse2/tests/test_bulletin.py
+++ b/obspy/io/gse2/tests/test_bulletin.py
@@ -263,7 +263,7 @@ def test_magnitude(self):
         self.assertEqual(mag_1.evaluation_status, None)
         self.assertNotEqual(mag_1.creation_info, None)
         self.assertEqual(len(mag_1.comments), 0)
-        self.assertEqual(len(mag_1.station_magnitude_contributions), 0)
+        self.assertEqual(len(mag_1.station_magnitude_contributions), 3)
         # Test second Magnitude
         mag_2 = magnitudes[1]
         self.assertEqual(
@@ -278,8 +278,8 @@ def test_magnitude(self):
         self.assertEqual(mag_2.evaluation_mode, None)
         self.assertEqual(mag_2.evaluation_status, None)
         self.assertNotEqual(mag_2.creation_info, None)
-        self.assertEqual(len(mag_1.comments), 0)
-        self.assertEqual(len(mag_1.station_magnitude_contributions), 0)
+        self.assertEqual(len(mag_2.comments), 0)
+        self.assertEqual(len(mag_2.station_magnitude_contributions), 1)
 
     def test_station_magnitude(self):
         """
@@ -299,9 +299,16 @@ def test_station_magnitude(self):
         self.assertEqual(sta_mag_1.station_magnitude_type, 'ML')
         self.assertEqual(sta_mag_1.amplitude_id, 'smi:local/amplitude/3586432')
         self.assertEqual(sta_mag_1.method_id, None)
-        self.assertEqual(sta_mag_1.waveform_id, None)
         self.assertNotEqual(sta_mag_1.creation_info, None)
         self.assertEqual(len(sta_mag_1.comments), 0)
+
+        waveform_1 = sta_mag_1.waveform_id
+        self.assertEqual(waveform_1.network_code, 'XX')
+        self.assertEqual(waveform_1.station_code, 'GERES')
+        self.assertEqual(waveform_1.channel_code, None)
+        self.assertEqual(waveform_1.location_code, None)
+        self.assertEqual(waveform_1.resource_uri, None)
+
         # Test second StationMagnitude
         sta_mag_2 = station_magnitudes[1]
         self.assertEqual(
@@ -311,10 +318,16 @@ def test_station_magnitude(self):
         self.assertEqual(sta_mag_2.station_magnitude_type, 'mb')
         self.assertEqual(sta_mag_2.amplitude_id, 'smi:local/amplitude/3586555')
         self.assertEqual(sta_mag_2.method_id, None)
-        self.assertEqual(sta_mag_2.waveform_id, None)
         self.assertNotEqual(sta_mag_2.creation_info, None)
         self.assertEqual(len(sta_mag_2.comments), 0)
 
+        waveform_2 = sta_mag_2.waveform_id
+        self.assertEqual(waveform_2.network_code, 'XX')
+        self.assertEqual(waveform_2.station_code, 'FINES')
+        self.assertEqual(waveform_2.channel_code, None)
+        self.assertEqual(waveform_2.location_code, None)
+        self.assertEqual(waveform_2.resource_uri, None)
+
     def test_amplitude(self):
         """
         Test Amplitude object.