pysmo.functions
Building-block functions for pysmo types.
The pysmo.functions module provides low-level functions that perform
common operations on pysmo types. They are intended as building blocks
for constructing more complex processing workflows.
Many functions accept a clone argument that controls whether the function
operates on the input directly or first creates a clone (via
deepcopy) and returns the modified copy. For example:
>>> from pysmo.functions import resample
>>> from pysmo.classes import SAC
>>> sac_seis = SAC.from_file("example.sac").seismogram
>>> new_delta = sac_seis.delta * 2
>>>
>>> # create a clone and modify data in clone instead of sac_seis:
>>> new_sac_seis = resample(sac_seis, new_delta, clone=True)
>>>
>>> # modify data in sac_seis directly:
>>> resample(sac_seis, new_delta)
>>>
>>> # because the deepcopy operation can be computationaly expensive,
>>> # you should NOT use the following pattern:
>>> sac_seis = resample(sac_seis, new_delta, clone=True)
>>>
Hint
Additional functions may be found in pysmo.tools.
Functions:
| Name | Description |
|---|---|
clone_to_mini |
Create a new instance of a Mini class from a matching other one. |
copy_from_mini |
Copy attributes from a Mini instance to matching other one. |
crop |
Shorten a seismogram by providing new begin and end times. |
detrend |
Remove linear and/or constant trends from a seismogram. |
normalize |
Normalize a seismogram with its absolute max value. |
pad |
Pad seismogram data. |
resample |
Resample Seismogram data using the Fourier method. |
taper |
Apply a symmetric taper to the ends of a Seismogram. |
time2index |
Converts a specific timestamp to the corresponding data array index. |
window |
Returns an optionally padded and tapered window of a seismogram. |
clone_to_mini
Create a new instance of a Mini class from a matching other one.
This function creates a clone of an existing class by
copying the attributes defined in mini_cls from the source
to the target. Attributes only present in the source object are ignored,
potentially resulting in a smaller and more performant object.
If the source instance is missing an attribute for which a default is defined in the target class, then that default value for that attribute is used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mini_cls
|
type[TMini]
|
The type of Mini class to create. |
required |
source
|
_AnyProto
|
The instance to clone (must contain all attributes present
in |
required |
update
|
dict | None
|
Update or add attributes in the returned |
None
|
Returns:
| Type | Description |
|---|---|
TMini
|
A new Mini instance type mini_cls. |
Raises:
| Type | Description |
|---|---|
AttributeError
|
If the |
Examples:
Create a MiniSeismogram from a
SacSeismogram instance with
a new begin_time.
>>> from pysmo.functions import clone_to_mini
>>> from pysmo import MiniSeismogram
>>> from pysmo.classes import SAC
>>> from pandas import Timestamp
>>> from datetime import timezone
>>> now = Timestamp.now(timezone.utc)
>>> sac_seismogram = SAC.from_file("example.sac").seismogram
>>> mini_seismogram = clone_to_mini(MiniSeismogram, sac_seismogram, update={"begin_time": now})
>>> all(sac_seismogram.data == mini_seismogram.data)
True
>>> mini_seismogram.begin_time == now
True
>>>
See Also
copy_from_mini: Copy attributes
from a Mini instance to matching other one.
Source code in src/pysmo/functions/_utils.py
copy_from_mini
Copy attributes from a Mini instance to matching other one.
This function copies all attributes in the source Mini class
instance to a compatible target instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
_AnyMini
|
The Mini instance to copy attributes from. |
required |
target
|
_AnyProto
|
Compatible target instance. |
required |
update
|
dict | None
|
Update or add attributes in the target instance. |
None
|
Raises:
| Type | Description |
|---|---|
AttributeError
|
If the |
See Also
clone_to_mini: Create a new
instance of a Mini class from a matching other one.
Source code in src/pysmo/functions/_utils.py
crop
Shorten a seismogram by providing new begin and end times.
This function calculates the indices corresponding to the provided new
begin and end times using time2index, then
slices the seismogram data array accordingly and updates the
begin_time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seismogram
|
T
|
|
required |
begin_time
|
Timestamp
|
New begin time. |
required |
end_time
|
Timestamp
|
New end time. |
required |
clone
|
bool
|
Operate on a clone of the input seismogram. |
False
|
Returns:
| Type | Description |
|---|---|
None | T
|
Cropped |
Raises:
| Type | Description |
|---|---|
ValueError
|
If new begin time is after new end time. |
Examples:
>>> from pysmo.functions import crop
>>> from pysmo.classes import SAC
>>> from pandas import Timedelta
>>> sac_seis = SAC.from_file("example.sac").seismogram
>>> new_begin_time = sac_seis.begin_time + Timedelta(seconds=10)
>>> new_end_time = sac_seis.end_time - Timedelta(seconds=10)
>>> crop(sac_seis, new_begin_time, new_end_time)
>>>
Source code in src/pysmo/functions/_seismogram.py
detrend
detrend(seismogram: T, clone: bool = False) -> None | T
Remove linear and/or constant trends from a seismogram.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seismogram
|
T
|
Seismogram object. |
required |
clone
|
bool
|
Operate on a clone of the input seismogram. |
False
|
Returns:
| Type | Description |
|---|---|
None | T
|
Detrended |
Examples:
>>> import numpy as np
>>> import pytest
>>> from pysmo.functions import detrend
>>> from pysmo.classes import SAC
>>> sac_seis = SAC.from_file("example.sac").seismogram
>>> 0 == pytest.approx(np.mean(sac_seis.data), abs=1e-11)
np.False_
>>> detrend(sac_seis)
>>> 0 == pytest.approx(np.mean(sac_seis.data), abs=1e-11)
np.True_
>>>
Source code in src/pysmo/functions/_seismogram.py
normalize
normalize(
seismogram: T,
t1: Timestamp | None = None,
t2: Timestamp | None = None,
clone: bool = False,
) -> None | T
Normalize a seismogram with its absolute max value.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seismogram
|
T
|
Seismogram object. |
required |
t1
|
Timestamp | None
|
Optionally restrict searching of maximum to time after this time. |
None
|
t2
|
Timestamp | None
|
Optionally restrict searching of maximum to time before this time. |
None
|
clone
|
bool
|
Operate on a clone of the input seismogram. |
False
|
Returns:
| Type | Description |
|---|---|
None | T
|
Normalized |
Examples:
>>> import numpy as np
>>> from pysmo.functions import normalize
>>> from pysmo.classes import SAC
>>> sac_seis = SAC.from_file("example.sac").seismogram
>>> normalize(sac_seis)
>>> -1 <= np.max(sac_seis.data) <= 1
np.True_
>>>
Source code in src/pysmo/functions/_seismogram.py
pad
pad(
seismogram: T,
begin_time: Timestamp,
end_time: Timestamp,
mode: _ModeKind | _ModeFunc = "constant",
clone: bool = False,
**kwargs: Any
) -> None | T
Pad seismogram data.
This function calculates the indices corresponding to the provided new
begin and end times using time2index, then
pads the data array using
numpy.pad and updates the
begin_time. Note that the actual begin and
end times are set by indexing, so they may be slightly different than the
provided input begin and end times.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seismogram
|
T
|
|
required |
begin_time
|
Timestamp
|
New begin time. |
required |
end_time
|
Timestamp
|
New end time. |
required |
mode
|
_ModeKind | _ModeFunc
|
Pad mode to use (see |
'constant'
|
clone
|
bool
|
Operate on a clone of the input seismogram. |
False
|
kwargs
|
Any
|
Keyword arguments to pass to |
{}
|
Returns:
| Type | Description |
|---|---|
None | T
|
Padded |
Raises:
| Type | Description |
|---|---|
ValueError
|
If new begin time is after new end time. |
Examples:
>>> from pysmo.functions import pad
>>> from pysmo.classes import SAC
>>> from pandas import Timedelta
>>> import numpy as np
>>>
>>> sac_seis = SAC.from_file("example.sac").seismogram
>>> original_length = len(sac_seis.data)
>>> sac_seis.data
array([2302., 2313., 2345., ..., 2836., 2772., 2723.], shape=(180000,))
>>> new_begin_time = sac_seis.begin_time - Timedelta(seconds=10)
>>> new_end_time = sac_seis.end_time + Timedelta(seconds=10)
>>> pad(sac_seis, new_begin_time, new_end_time)
>>> np.isclose(len(sac_seis.data), original_length + 20 / sac_seis.delta.total_seconds())
np.True_
>>> sac_seis.data
array([0., 0., 0., ..., 0., 0., 0.], shape=(181000,))
>>>
Source code in src/pysmo/functions/_seismogram.py
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 | |
resample
resample(
seismogram: T,
delta: PositiveTimedelta,
clone: bool = False,
) -> None | T
Resample Seismogram data using the Fourier method.
This function uses scipy.resample to resample
the data to a new sampling interval. If the new sampling interval is
identical to the current one, no action is taken.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seismogram
|
T
|
Seismogram object. |
required |
delta
|
PositiveTimedelta
|
New sampling interval. |
required |
clone
|
bool
|
Operate on a clone of the input seismogram. |
False
|
Returns:
| Type | Description |
|---|---|
None | T
|
Resampled |
Examples:
>>> from pysmo.functions import resample
>>> from pysmo.classes import SAC
>>> sac_seis = SAC.from_file("example.sac").seismogram
>>> len(sac_seis.data)
180000
>>> original_delta = sac_seis.delta
>>> new_delta = original_delta * 2
>>> resample(sac_seis, new_delta)
>>> len(sac_seis.data)
90000
>>>
Source code in src/pysmo/functions/_seismogram.py
taper
taper(
seismogram: T,
taper_width: NonNegativeTimedelta | UnitFloat,
window_type: _WindowType = "hann",
clone: bool = False,
) -> None | T
Apply a symmetric taper to the ends of a Seismogram.
The taper() function applies a symmetric taper to
the data of a Seismogram object. The taper width is
understood as the portion of the seismogram affected by the taper window
function. It can be provided as an absolute duration (non-negative
Timedelta), or as a fraction of seismogram length
(float between 0 and 1). Internally, absolute durations are
converted to fractions by dividing by the total seismogram duration, and
absolute durations should therefore not exceed the total seismogram
duration.
The shape of the windowing function is calculated by calling the scipy
get_window() function using the number
of samples corresponding to the fraction specified above, then it is split
in half and applied to the beginning and end of the seismogram data. Thus
taper_width=0 corresponds to a rectangular window (i.e. no tapering), and
taper_width=1 to a symmetric taper applied to the entire length of the
seismogram. A value of e.g. 0.5 applies the "ramp up" portion of the
window to the first quarter of the seismogram, while the "ramp down" portion
of the window is applied to the last quarter.
Warning
The scipy get_window() function
is a helper function that calculates a large variety of window shapes,
which do not all make sense in this application (e.g. boxcar or tukey).
Users are encouraged to read the documentation of the actual window
functions available via
get_window() to see if they can be
split in the middle and used as "ramp up" and "ramp down" functions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seismogram
|
T
|
Seismogram object. |
required |
taper_width
|
NonNegativeTimedelta | UnitFloat
|
Width of the taper to use. |
required |
window_type
|
_WindowType
|
Function to calculate taper shape (see
|
'hann'
|
clone
|
bool
|
Operate on a clone of the input seismogram. |
False
|
Returns:
| Type | Description |
|---|---|
None | T
|
Tapered |
Examples:
>>> from pysmo.functions import taper, detrend
>>> from pysmo.classes import SAC
>>> sac_seis = SAC.from_file("example.sac").seismogram
>>> detrend(sac_seis)
>>> sac_seis.data
array([ 95.59652208, 106.59521819, 138.59391429, ..., 394.90004126,
330.89873737, 281.89743348], shape=(180000,))
>>> taper(sac_seis, 0.2)
>>> sac_seis.data
array([0.00000000e+00, 8.11814104e-07, 4.22204657e-06, ...,
1.20300114e-05, 2.52007798e-06, 0.00000000e+00], shape=(180000,))
>>>
Source code in src/pysmo/functions/_seismogram.py
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 | |
time2index
time2index(
seismogram: Seismogram,
time: Timestamp,
allow_out_of_bounds: bool = False,
) -> int
Converts a specific timestamp to the corresponding data array index.
Seismic data is sampled at discrete intervals. When a requested time does not align perfectly with a sample, this function selects the nearest index using the following rules:
- If the time is within 0.1% of a sample interval of an integer, it "snaps" to that integer to account for floating-point jitter.
- Use standard rounding (0.5 rounds up to the next index) otherwise.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seismogram
|
Seismogram
|
Seismogram object. |
required |
time
|
Timestamp
|
The absolute time to convert. |
required |
allow_out_of_bounds
|
bool
|
If True, returns the calculated index even if it falls outside the seismogram's data range [0, len-1]. |
False
|
Returns:
| Type | Description |
|---|---|
int
|
The index of the sample closest to the provided time. |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the calculated index is outside the data array and
|
Source code in src/pysmo/functions/_seismogram.py
window
window(
seismogram: T,
window_begin_time: Timestamp,
window_end_time: Timestamp,
ramp_width: NonNegativeTimedelta | NonNegativeNumber,
window_type: _WindowType = "hann",
same_shape: bool = False,
clone: bool = False,
) -> None | T
Returns an optionally padded and tapered window of a seismogram.
This function combines the crop,
detrend, taper, and
optionally pad functions to return a 'windowed'
seismogram. Its purpose is to focus on a specific time window of interest,
while also (optionally) preserving the original seismogram length and
tapering the signal before and after the window.
Tip
Note that the window defined by window_begin_time and
window_end_time excludes the tapered sections, so the total length
of the window will be the provided window length plus the tapered
sections of the signal. This behaviour is a bit different from
taper(), where the taper is applied to the
entire signal. In a sense the tapering here is applied to the 'outside'
of the region of interest rather than the 'inside'.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
seismogram
|
T
|
Seismogram object. |
required |
window_begin_time
|
Timestamp
|
Begin time of the window. |
required |
window_end_time
|
Timestamp
|
End time of the window. |
required |
ramp_width
|
NonNegativeTimedelta | NonNegativeNumber
|
Duration of the taper on each side.
Note: Total duration = window length + (2 * |
required |
window_type
|
_WindowType
|
Taper method to use (see |
'hann'
|
same_shape
|
bool
|
If True, pad the seismogram to its original length after windowing. |
False
|
clone
|
bool
|
Operate on a clone of the input seismogram. |
False
|
Returns:
| Type | Description |
|---|---|
None | T
|
Windowed |
Examples:
In this example we focus on a window starting 500 seconds after the
begin_time of the seismogram and lasting for 1000 seconds. Setting the
ramp_width to 250 seconds means that the actual window will start 250
seconds earlier and end 250 seconds later than the specified window
begin and end times.
>>> from pysmo.functions import window, detrend
>>> from pysmo.classes import SAC
>>> from pysmo.tools.plotutils import plotseis
>>> from pandas import Timedelta
>>>
>>> sac_seis = SAC.from_file("example.sac").seismogram
>>> ramp_width = Timedelta(seconds=250)
>>> window_begin_time = sac_seis.begin_time + Timedelta(seconds=500)
>>> window_end_time = window_begin_time + Timedelta(seconds=1000)
>>> windowed_seis = window(sac_seis, window_begin_time, window_end_time, ramp_width, same_shape=True, clone=True)
>>> detrend(sac_seis)
>>> fig = plotseis(sac_seis, windowed_seis)
>>>
Source code in src/pysmo/functions/_seismogram.py
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 | |