def test_equality_methods():
    """
    Tests the (in)equality methods of source and receiver objects. They both
    inherit from the same base class thus they are tested here - but it
    would also be suitable for the receiver tests.
    """
    src1 = Source(latitude=1, longitude=2)
    src2 = Source(latitude=3, longitude=3)
    rec1 = Receiver(latitude=1, longitude=2)
    rec2 = Receiver(latitude=3, longitude=3)

    assert src1 == src1
    assert src2 == src2
    assert rec1 == rec1
    assert rec2 == rec2

    assert src1 != src2
    assert src1 != rec1
    assert src1 != rec2

    assert src2 != src1
    assert src2 != rec1
    assert src2 != rec2

    assert rec1 != rec2
    assert rec1 != src1
    assert rec1 != src2

    assert rec2 != src1
    assert rec2 != src1
    assert rec2 != src2
def test_parse_obspy_objects():
    """
    Tests parsing from ObsPy objects.
    """
    cat = obspy.read_events(EVENT_FILE)
    ev = cat[0]

    _assert_src(Source.parse(cat))
    _assert_src(Source.parse(ev))
Example #3
0
def test_parse_obspy_objects():
    """
    Tests parsing from ObsPy objects.
    """
    cat = obspy.read_events(EVENT_FILE)
    ev = cat[0]

    _assert_src(Source.parse(cat))
    _assert_src(Source.parse(ev))
Example #4
0
def test_parse_CMTSOLUTIONS_file(tmpdir):
    """
    Tests parsing from a CMTSOLUTIONS file.
    """
    filename = os.path.join(str(tmpdir), "CMTSOLUTIONS")
    lines = (
        "PDEW2011  8 23 17 51  4.60  37.9400  -77.9300   6.0 5.9 5.8 VIRGINIA",
        "event name:     201108231751A",
        "time shift:      1.1100",
        "half duration:   1.8000",
        "latitude:       37.9100",
        "longitude:     -77.9300",
        "depth:          12.0000",
        "Mrr:       4.710000e+24",
        "Mtt:       3.810000e+22",
        "Mpp:      -4.740000e+24",
        "Mrt:       3.990000e+23",
        "Mrp:      -8.050000e+23",
        "Mtp:      -1.230000e+24")
    with open(filename, "wt") as fh:
        fh.write("\n".join(lines))

    origin_time = obspy.UTCDateTime(2011, 8, 23, 17, 51, 4.6)

    src = Source.parse(filename)
    src_params = np.array([src.latitude, src.longitude, src.depth_in_m,
                           src.m_rr, src.m_tt, src.m_pp, src.m_rt, src.m_rp,
                           src.m_tp], dtype="float64")
    # Latitude will have assumed to be WGS84 and converted to geocentric
    # latitude.
    np.testing.assert_allclose(src_params, np.array(
        (elliptic_to_geocentric_latitude(37.91), -77.93, 12000, 4.71E17,
         3.81E15, -4.74E17, 3.99E16, -8.05E16,
         -1.23E17), dtype="float64"))
    assert src.origin_time == origin_time

    # Write again. Reset latitude beforehand.
    filename = os.path.join(str(tmpdir), "CMTSOLUTIONS2")
    src.latitude = 37.91
    src.write_CMTSOLUTION_file(filename)

    # This time there is no need to convert latitudes. Writing will convert
    # to WGS84 and reading will convert back.
    src = Source.parse(filename)
    src_params = np.array([src.latitude, src.longitude, src.depth_in_m,
                           src.m_rr, src.m_tt, src.m_pp, src.m_rt, src.m_rp,
                           src.m_tp], dtype="float64")
    np.testing.assert_allclose(src_params, np.array(
        (37.91, -77.93, 12000, 4.71E17, 3.81E15, -4.74E17, 3.99E16, -8.05E16,
         -1.23E17), dtype="float64"), rtol=1E-5)
    assert src.origin_time == origin_time
Example #5
0
def test_print_regressions():
    """
    Guard against a regression for printing a source object.
    """
    src = Source.from_strike_dip_rake(
        latitude=27.77,
        longitude=85.37,
        depth_in_m=12000.0,
        M0=1e21,
        strike=32.0,
        dip=62.0,
        rake=90.0,
    )
    assert (str(src)) == ("Instaseis Source:\n"
                          "\tOrigin Time      : 1970-01-01T00:00:00.000000Z\n"
                          "\tLongitude        :   85.4 deg\n"
                          "\tLatitude         :   27.8 deg\n"
                          "\tDepth            : 1.2e+01 km km\n"
                          "\tMoment Magnitude :   7.93\n"
                          "\tScalar Moment    :   1.00e+21 Nm\n"
                          "\tMrr              :   8.29e+20 Nm\n"
                          "\tMtt              :  -2.33e+20 Nm\n"
                          "\tMpp              :  -5.96e+20 Nm\n"
                          "\tMrt              :   2.96e+20 Nm\n"
                          "\tMrp              :   4.74e+20 Nm\n"
                          "\tMtp              :  -3.73e+20 Nm\n")
Example #6
0
def test_parse_cmtsolutions_file(tmpdir):
    """
    Tests parsing from a CMTSOLUTIONS file.
    """
    filename = os.path.join(str(tmpdir), "CMTSOLUTIONS")
    lines = (" PDE 2011  8 23 17 51  4.60  37.9400  -77.9300   6.0 5.9 5.8 "
             "VIRGINIA", "event name:     201108231751A",
             "time shift:      1.00", "half duration:   1.8000",
             "latitude:       37.9100", "longitude:     -77.9300",
             "depth:          12.0000", "Mrr:       4.710000e+24",
             "Mtt:       3.810000e+22", "Mpp:      -4.740000e+24",
             "Mrt:       3.990000e+23", "Mrp:      -8.050000e+23",
             "Mtp:      -1.230000e+24")
    with open(filename, "wt") as fh:
        fh.write("\n".join(lines))

    # This is the hypocentral time + 1 seconds (the time shift in the
    # CMTSOLUTION file).
    origin_time = obspy.UTCDateTime(2011, 8, 23, 17, 51, 5.6)

    src = Source.parse(filename)
    src_params = np.array([
        src.latitude, src.longitude, src.depth_in_m, src.m_rr, src.m_tt,
        src.m_pp, src.m_rt, src.m_rp, src.m_tp
    ],
                          dtype="float64")
    # Latitude will have assumed to be WGS84 and converted to geocentric
    # latitude. The import machinery should do that.
    np.testing.assert_allclose(
        src_params,
        np.array((elliptic_to_geocentric_latitude(37.91), -77.93, 12000,
                  4.71E17, 3.81E15, -4.74E17, 3.99E16, -8.05E16, -1.23E17),
                 dtype="float64"))
    assert src.origin_time == origin_time
Example #7
0
 def focmec(self):
     if self.ui.source_tab.currentIndex() == 0:
         return [
             float(self.ui.m_rr.value()),
             float(self.ui.m_tt.value()),
             float(self.ui.m_pp.value()),
             float(self.ui.m_rt.value()),
             float(self.ui.m_rp.value()),
             float(self.ui.m_tp.value()),
         ]
     elif self.ui.source_tab.currentIndex() == 1:
         source = Source.from_strike_dip_rake(
             latitude=float(self.ui.source_latitude.value()),
             longitude=float(self.ui.source_longitude.value()),
             depth_in_m=float(self.source_depth) * 1000.0,
             strike=float(self.ui.strike_slider.value()),
             dip=float(self.ui.dip_slider.value()),
             rake=float(self.ui.rake_slider.value()),
             M0=1e16,
         )
         return [
             source.m_rr,
             source.m_tt,
             source.m_pp,
             source.m_rt,
             source.m_rp,
             source.m_tp,
         ]
def test_finite_source():
    """
    incremental tests of bwd mode with source force
    """
    from obspy.signal.filter import lowpass
    instaseis_bwd = InstaSeisDB(os.path.join(DATA, "100s_db_bwd_displ_only"))

    receiver = Receiver(latitude=42.6390, longitude=74.4940)

    source = Source(
        latitude=89.91, longitude=0.0, depth_in_m=12000,
        m_rr=4.710000e+24 / 1E7,
        m_tt=3.810000e+22 / 1E7,
        m_pp=-4.740000e+24 / 1E7,
        m_rt=3.990000e+23 / 1E7,
        m_rp=-8.050000e+23 / 1E7,
        m_tp=-1.230000e+24 / 1E7)

    dt = instaseis_bwd.dt
    sliprate = np.zeros(1000)
    sliprate[0] = 1.
    sliprate = lowpass(sliprate, 1./100., 1./dt, corners=4)

    source.set_sliprate(sliprate, dt, time_shift=0., normalize=True)

    st_fin = instaseis_bwd.get_seismograms_finite_source(
        sources=[source], receiver=receiver,
        components=('Z', 'N', 'E', 'R', 'T'), dt=0.1)
    st_ref = instaseis_bwd.get_seismograms(
        source=source, receiver=receiver,
        components=('Z', 'N', 'E', 'R', 'T'), dt=0.1, reconvolve_stf=True)

    np.testing.assert_allclose(st_fin.select(component='Z')[0].data,
                               st_ref.select(component='Z')[0].data,
                               rtol=1E-7, atol=1E-12)
    np.testing.assert_allclose(st_fin.select(component='N')[0].data,
                               st_ref.select(component='N')[0].data,
                               rtol=1E-7, atol=1E-12)
    np.testing.assert_allclose(st_fin.select(component='E')[0].data,
                               st_ref.select(component='E')[0].data,
                               rtol=1E-7, atol=1E-12)
    np.testing.assert_allclose(st_fin.select(component='R')[0].data,
                               st_ref.select(component='R')[0].data,
                               rtol=1E-7, atol=1E-12)
    np.testing.assert_allclose(st_fin.select(component='T')[0].data,
                               st_ref.select(component='T')[0].data,
                               rtol=1E-7, atol=1E-12)
Example #9
0
 def iterate(self):
     rec = Receiver(latitude=20, longitude=20)
     lat = random.random() * 0.5
     lat += 44
     lng = random.random() * 0.5
     lng += 44
     depth_in_m = random.random() * 50000
     src = Source(latitude=lat, longitude=lng, depth_in_m=depth_in_m)
     self.db.get_seismograms(source=src, receiver=rec)
Example #10
0
def test_m0():
    """
    Tests computation of scalar Moment.
    """
    strike = 10.0
    dip = 20.0
    rake = 30.0
    m0 = 1e16
    source = Source.from_strike_dip_rake(0.0, 0.0, 0.0, strike, dip, rake, m0)

    assert source.M0 == m0
Example #11
0
def test_m0():
    """
    Tests computation of scalar Moment.
    """
    strike = 10.
    dip = 20.
    rake = 30.
    m0 = 1e16
    source = Source.from_strike_dip_rake(0., 0., 0., strike, dip, rake, m0)

    assert source.M0 == m0
Example #12
0
 def source(self):
     fm = self.focmec
     return Source(latitude=float(self.ui.source_latitude.value()),
                   longitude=float(self.ui.source_longitude.value()),
                   depth_in_m=float(self.source_depth) * 1000.0,
                   m_rr=fm[0],
                   m_tt=fm[1],
                   m_pp=fm[2],
                   m_rt=fm[3],
                   m_rp=fm[4],
                   m_tp=fm[5])
Example #13
0
def test_M0():
    """
    Tests computation of scalar Moment.
    """
    strike = 10.
    dip = 20.
    rake = 30.
    M0 = 1e16
    source = Source.from_strike_dip_rake(0., 0., 0., strike, dip, rake, M0)

    assert source.M0 == M0
Example #14
0
    def iterate(self):
        # Random points on a sphere.
        lat = np.rad2deg(np.arcsin(2 * random.random() - 1))
        lng = random.random() * 360.0 - 180.0
        rec = Receiver(latitude=lat, longitude=lng)

        lat = np.rad2deg(np.arcsin(2 * random.random() - 1))
        lng = random.random() * 360.0 - 180.0
        depth_in_m = random.random() * self.max_depth
        src = Source(latitude=lat, longitude=lng, depth_in_m=depth_in_m)

        self.db.get_seismograms(source=src, receiver=rec)
Example #15
0
def test_sliprate_convenience_methods_finite_source():
    """
    Tests some convenience methods of sliprates for finite sources.
    """
    src = Source(latitude=0.0, longitude=90.0)
    fs = FiniteSource(pointsources=[src])
    fs.set_sliprate_dirac(2.0, 5)
    np.testing.assert_allclose(np.array([0.5, 0, 0, 0, 0]), src.sliprate)

    src = Source(latitude=0.0, longitude=90.0)
    fs = FiniteSource(pointsources=[src])
    fs.set_sliprate_lp(2.0, 5, 0.1)
    np.testing.assert_allclose(np.array(
        [0.023291, 0.111382, 0.211022, 0.186723, 0.045481]), src.sliprate,
        rtol=1E-3)

    src = Source(latitude=0.0, longitude=90.0)
    src.sliprate = np.ones(5)
    src.dt = 0.25
    fs = FiniteSource(pointsources=[src])
    fs.normalize_sliprate()
    np.testing.assert_allclose(np.ones(5), src.sliprate)
Example #16
0
    def iterate(self):
        if self.current_depth_counter >= self.depth_count:
            self.counter += 1
            self.current_depth_counter = 0

        # Fix latitude.
        lat = 0.0
        # Longitude values increase in 1 km steps.
        lng = self.counter * 0.01
        src = Source(latitude=lat,
                     longitude=lng,
                     depth_in_m=self.depths[self.current_depth_counter])

        self.db.get_seismograms(source=src, receiver=self.rec)
        self.current_depth_counter += 1
Example #17
0
def test_str_method_of_src():
    src = Source(latitude=0.0, longitude=90.0)
    assert str(src) == ("Instaseis Source:\n"
                        "\tOrigin Time      : 1970-01-01T00:00:00.000000Z\n"
                        "\tLongitude        :   90.0 deg\n"
                        "\tLatitude         :    0.0 deg\n"
                        "\tDepth            :  not set km\n"
                        "\tMoment Magnitude :   -inf\n"
                        "\tScalar Moment    :   0.00e+00 Nm\n"
                        "\tMrr              :   0.00e+00 Nm\n"
                        "\tMtt              :   0.00e+00 Nm\n"
                        "\tMpp              :   0.00e+00 Nm\n"
                        "\tMrt              :   0.00e+00 Nm\n"
                        "\tMrp              :   0.00e+00 Nm\n"
                        "\tMtp              :   0.00e+00 Nm\n")
Example #18
0
 def focmec(self):
     if self.ui.source_tab.currentIndex() == 0:
         return [float(self.ui.m_rr.value()), float(self.ui.m_tt.value()),
                 float(self.ui.m_pp.value()), float(self.ui.m_rt.value()),
                 float(self.ui.m_rp.value()), float(self.ui.m_tp.value())]
     elif self.ui.source_tab.currentIndex() == 1:
         source = Source.from_strike_dip_rake(
             latitude=float(self.ui.source_latitude.value()),
             longitude=float(self.ui.source_longitude.value()),
             depth_in_m=float(self.source_depth) * 1000.0,
             strike=float(self.ui.strike_slider.value()),
             dip=float(self.ui.dip_slider.value()),
             rake=float(self.ui.rake_slider.value()),
             M0=1E16)
         return [source.m_rr, source.m_tt,
                 source.m_pp, source.m_rt,
                 source.m_rp, source.m_tp]
Example #19
0
    def on_load_source_button_released(self):
        pwd = os.getcwd()
        self.source_file = str(QtGui.QFileDialog.getOpenFileName(self, "Choose Source File", pwd))
        if not self.source_file:
            return

        s = Source.parse(self.source_file)
        self.ui.m_rr.setValue(s.m_rr)
        self.ui.m_pp.setValue(s.m_pp)
        self.ui.m_rp.setValue(s.m_rp)
        self.ui.m_tt.setValue(s.m_tt)
        self.ui.m_rt.setValue(s.m_rt)
        self.ui.m_tp.setValue(s.m_tp)

        self.ui.source_longitude.setValue(s.longitude)
        self.ui.source_latitude.setValue(s.latitude)
        self.ui.depth_slider.setValue(-s.depth_in_m / 1e3)
        self.set_info()
Example #20
0
    def on_load_source_button_released(self):
        pwd = os.getcwd()
        self.source_file = str(
            QtGui.QFileDialog.getOpenFileName(self, "Choose Source File", pwd))
        if not self.source_file:
            return

        s = Source.parse(self.source_file)
        self.ui.m_rr.setValue(s.m_rr)
        self.ui.m_pp.setValue(s.m_pp)
        self.ui.m_rp.setValue(s.m_rp)
        self.ui.m_tt.setValue(s.m_tt)
        self.ui.m_rt.setValue(s.m_rt)
        self.ui.m_tp.setValue(s.m_tp)

        self.ui.source_longitude.setValue(s.longitude)
        self.ui.source_latitude.setValue(s.latitude)
        self.ui.depth_slider.setValue(-s.depth_in_m / 1e3)
        self.set_info()
Example #21
0
def test_sliprate_convenience_methods_finite_source():
    """
    Tests some convenience methods of sliprates for finite sources.
    """
    src = Source(latitude=0.0, longitude=90.0)
    fs = FiniteSource(pointsources=[src])
    fs.set_sliprate_dirac(2.0, 5)
    np.testing.assert_allclose(np.array([0.5, 0, 0, 0, 0]), src.sliprate)

    src = Source(latitude=0.0, longitude=90.0)
    fs = FiniteSource(pointsources=[src])
    fs.set_sliprate_lp(2.0, 5, 0.1)
    np.testing.assert_allclose(np.array(
        [0.023291, 0.111382, 0.211022, 0.186723, 0.045481]), src.sliprate,
        rtol=1E-3)

    src = Source(latitude=0.0, longitude=90.0)
    src.sliprate = np.ones(5)
    src.dt = 0.25
    fs = FiniteSource(pointsources=[src])
    fs.normalize_sliprate()
    np.testing.assert_allclose(np.ones(5), src.sliprate)
Example #22
0
def test_print_regressions():
    """
    Guard against a regression for printing a source object.
    """
    src = Source.from_strike_dip_rake(
        latitude=27.77, longitude=85.37, depth_in_m=12000.0,
        M0=1e+21, strike=32., dip=62., rake=90.)
    assert(str(src)) == (
        "Instaseis Source:\n"
        "\tOrigin Time      : 1970-01-01T00:00:00.000000Z\n"
        "\tLongitude        :   85.4 deg\n"
        "\tLatitude         :   27.8 deg\n"
        "\tDepth            : 1.2e+01 km km\n"
        "\tMoment Magnitude :   7.93\n"
        "\tScalar Moment    :   1.00e+21 Nm\n"
        "\tMrr              :   8.29e+20 Nm\n"
        "\tMtt              :  -2.33e+20 Nm\n"
        "\tMpp              :  -5.96e+20 Nm\n"
        "\tMrt              :   2.96e+20 Nm\n"
        "\tMrp              :   4.74e+20 Nm\n"
        "\tMtp              :  -3.73e+20 Nm\n")
Example #23
0
def test_parse_cmtsolutions_file(tmpdir):
    """
    Tests parsing from a CMTSOLUTIONS file.
    """
    filename = os.path.join(str(tmpdir), "CMTSOLUTIONS")
    lines = (
        " PDE 2011  8 23 17 51  4.60  37.9400  -77.9300   6.0 5.9 5.8 "
        "VIRGINIA",
        "event name:     201108231751A",
        "time shift:      1.00",
        "half duration:   1.8000",
        "latitude:       37.9100",
        "longitude:     -77.9300",
        "depth:          12.0000",
        "Mrr:       4.710000e+24",
        "Mtt:       3.810000e+22",
        "Mpp:      -4.740000e+24",
        "Mrt:       3.990000e+23",
        "Mrp:      -8.050000e+23",
        "Mtp:      -1.230000e+24")
    with open(filename, "wt") as fh:
        fh.write("\n".join(lines))

    # This is the hypocentral time + 1 seconds (the time shift in the
    # CMTSOLUTION file).
    origin_time = obspy.UTCDateTime(2011, 8, 23, 17, 51, 5.6)

    src = Source.parse(filename)
    src_params = np.array([src.latitude, src.longitude, src.depth_in_m,
                           src.m_rr, src.m_tt, src.m_pp, src.m_rt, src.m_rp,
                           src.m_tp], dtype="float64")
    # Latitude will have assumed to be WGS84 and converted to geocentric
    # latitude. The import machinery should do that.
    np.testing.assert_allclose(src_params, np.array(
        (elliptic_to_geocentric_latitude(37.91), -77.93, 12000, 4.71E17,
         3.81E15, -4.74E17, 3.99E16, -8.05E16,
         -1.23E17), dtype="float64"))
    assert src.origin_time == origin_time
Example #24
0
def test_parse_quakeml():
    """
    Tests parsing from a QuakeML file.
    """
    src = Source.parse(EVENT_FILE)
    _assert_src(src)
Example #25
0
 def iterate(self):
     src = Source(latitude=10, longitude=10)
     rec = Receiver(latitude=20, longitude=20)
     self.db.get_seismograms(source=src,
                             receiver=rec,
                             return_obspy_stream=False)
Example #26
0
def test_event_parsing_failure_states():
    """
    Tests the failures when parsing an event.
    """
    # Random string.
    with pytest.raises(SourceParseError) as err:
        Source.parse("random strings")
    assert err.value.args[0] == "Could not parse the given source."

    # Empty catalog.
    cat = obspy.read_events()
    cat.events = []
    with pytest.raises(SourceParseError) as err:
        Source.parse(cat)
    assert err.value.args[0] == "Event catalog contains zero events."

    # Catalog with lots of events.
    cat = obspy.read_events()
    with pytest.raises(SourceParseError) as err:
        Source.parse(cat)
    assert err.value.args[0].startswith("Event catalog contains 3 events")

    event = obspy.read_events(EVENT_FILE)[0]

    # Event with no origin.
    ev = event.copy()
    ev.origins = []
    with pytest.raises(SourceParseError) as err:
        Source.parse(ev)
    assert err.value.args[0] == "Event must contain an origin."

    # Event with no focmec.
    ev = event.copy()
    ev.focal_mechanisms = []
    with pytest.raises(SourceParseError) as err:
        Source.parse(ev)
    assert err.value.args[0] == "Event must contain a focal mechanism."

    # Event with no moment tensor.
    ev = event.copy()
    ev.focal_mechanisms[0].moment_tensor = None
    # Force this to None to prevent the resource id mechanism to "resurrect"
    # the focal mechanism.
    ev.preferred_focal_mechanism_id = None
    with pytest.raises(SourceParseError) as err:
        Source.parse(ev)
    assert err.value.args[0] == "Event must contain a moment tensor."
Example #27
0
 def iterate(self):
     src = Source(latitude=10, longitude=10)
     rec = Receiver(latitude=20, longitude=20)
     self.db.get_seismograms(source=src, receiver=rec)
Example #28
0
def test_parse_QuakeML():
    """
    Tests parsing from a QuakeML file.
    """
    src = Source.parse(EVENT_FILE)
    _assert_src(src)
Example #29
0
def test_event_parsing_failure_states():
    """
    Tests the failures when parsing an event.
    """
    # Random string.
    with pytest.raises(SourceParseError) as err:
        Source.parse("random strings")
    assert err.value.args[0] == "Could not parse the given source."

    # Empty catalog.
    cat = obspy.read_events()
    cat.events = []
    with pytest.raises(SourceParseError) as err:
        Source.parse(cat)
    assert err.value.args[0] == "Event catalog contains zero events."

    # Catalog with lots of events.
    cat = obspy.read_events()
    with pytest.raises(SourceParseError) as err:
        Source.parse(cat)
    assert err.value.args[0].startswith("Event catalog contains 3 events")

    event = obspy.read_events(EVENT_FILE)[0]

    # Event with no origin.
    ev = event.copy()
    ev.origins = []
    with pytest.raises(SourceParseError) as err:
        Source.parse(ev)
    assert err.value.args[0] == "Event must contain an origin."

    # Event with no focmec.
    ev = event.copy()
    ev.focal_mechanisms = []
    with pytest.raises(SourceParseError) as err:
        Source.parse(ev)
    assert err.value.args[0] == "Event must contain a focal mechanism."

    # Event with no moment tensor.
    ev = event.copy()
    ev.focal_mechanisms[0].moment_tensor = None
    # Force this to None to prevent the resource id mechanism to "resurrect"
    # the focal mechanism.
    ev.preferred_focal_mechanism_id = None
    with pytest.raises(SourceParseError) as err:
        Source.parse(ev)
    assert err.value.args[0] == "Event must contain a moment tensor."
Example #30
0
def test_radian_calculations():
    src = Source(latitude=90.0, longitude=180.0)
    assert np.isclose(src.latitude, 90.0)
    assert np.isclose(src.latitude_rad, np.pi / 2.0)
    assert np.isclose(src.longitude, 180.0)
    assert np.isclose(src.longitude_rad, np.pi)