pysmo.tools.iccs
#
Iterative Cross-Correlation and Stack (ICCS).
Warning
This module is being developed alongside a complete rewrite of AIMBAT. Expect major changes until the rewrite is complete.
The ICCS1 method is an iterative algorithm to rapidly determine the best fitting delay times between an arbitrary number of seismograms. In each iteration, individual seismograms are cross-correlated with the stack of all input seismograms to improve the previous (or initial) phase arrival picks.
The results of ICCS are are similar to those of the the MCCC2 method, while also requiring fewer cross-correlations to be computed (each individual seismogram is only cross-correlated with the stack, whereas in MCCC all seismograms are cross-correlated with each other). ICCS is therefore particularly useful to perepare data for a successful MCCC run (e.g. if the initial picks are calculated rather than hand picked).
The iccs
module requires seismograms containing extra
attributes specific to the ICCS method. Hence it provides a protocol class
(ICCSSeismogram
) and corresponding Mini
class (MiniICCSSeismogram
) for that
purpose. In addition to the common attributes of a
Seismogram
in pysmo, the following parameters are
required:
Attribute | Description |
---|---|
t0 |
Initial pick (typically computed). Serves as input only when t1 is not set. |
t1 |
Improved pick. Serves as both input (if not None ) and output (always) when running the ICCS algorithm. |
select |
Determines if a seismogram should be used for the stack. Can be automatically set when autoselect is True during a run. |
flip |
Determines if the seismogram data should be flipped (i.e. multiplied with -1) before using it in the stack and cross-correlation. Can be automatically set when autoflip is True during a run. |
The diagram below shows execution flow, and how the above parameters are used when the ICCS algorithm is executed (see here for parameters and default values)':
flowchart TD
Start(["ICCSSeismograms with initial parameters."])
Stack0["Generate windowed seismograms and create stack from them."]
C["Cross-correlate windowed seismograms with stack to obtain updated picks and normalised correlation coefficients."]
FlipQ{"Is **autoflip**
True?"}
Flip["Toggle **flip** attribute of seismograms with negative correlation coefficients."]
QualQ{"Is **autoselect**
True?"}
Qual1["Set **select** attribute of seismograms to False for poor quality seismograms."]
Stack1["Recompute windowed seismograms and stack with updated parameters."]
H{"Convergence
criteria met?"}
I{"Maximum
iterations
reached?"}
End(["ICCSSeismograms with updated **t1**, **flip**, and **select** parameters."])
Start --> Stack0 --> C --> FlipQ -->|No| QualQ -->|No| Stack1 --> H -->|No| I -->|No| C
FlipQ -->|Yes| Flip --> QualQ
QualQ -->|Yes| Qual1 --> Stack1
H -->|Yes| End
I -->|Yes| End
-
Lou, X., et al. “AIMBAT: A Python/Matplotlib Tool for Measuring Teleseismic Arrival Times.” Seismological Research Letters, vol. 84, no. 1, Jan. 2013, pp. 85–93, https://doi.org/10.1785/0220120033. ↩
-
VanDecar, J. C., and R. S. Crosson. “Determination of Teleseismic Relative Phase Arrival Times Using Multi-Channel Cross-Correlation and Least Squares.” Bulletin of the Seismological Society of America, vol. 80, no. 1, Feb. 1990, pp. 150–69, https://doi.org/10.1785/BSSA0800010150. ↩
Classes:
-
ICCS
–Class to store a list of
ICCSSeismograms
and run the ICCS algorithm. -
ICCSSeismogram
–Protocol class to define the
ICCSSeismogram
type. -
MiniICCSSeismogram
–Minimal implementation of the
ICCSSeismogram
type.
Functions:
-
plotstack
–Plot the ICCS stack.
-
stack_pick
–Manually pick
t1
in the stack and apply it to all seismograms. -
stack_tw_pick
–Pick new time window limits in the stack.
-
update_pick
–Update
t1
in all seismograms by the same amount.
ICCS
#
Class to store a list of ICCSSeismograms
and run the ICCS algorithm.
The ICCS
class serves as a container to store a
list of seismograms (typically recordings of the same event at different
stations), and to then run the ICCS algorithm when an instance of this
class is called. Processing parameters that are common to all seismograms
are stored as attributes (e.g. time window limits).
Examples:
We begin with a set of SAC files of the same event, recorded at different
stations. All files have a preliminary phase arrival estimate saved in the
T0
SAC header, so we can use these files to create instances of the
MiniICCSSeismogram
class for use
with the ICCS
class:
>>> from pysmo.classes import SAC
>>> from pysmo.functions import clone_to_mini
>>> from pysmo.tools.iccs import MiniICCSSeismogram
>>> from pathlib import Path
>>>
>>> sacfiles = sorted(Path("iccs-example/").glob("*.bhz"))
>>>
>>> seismograms = []
>>> for sacfile in sacfiles:
... sac = SAC.from_file(sacfile)
... update = {"t0": sac.timestamps.t0}
... iccs_seismogram = clone_to_mini(MiniICCSSeismogram, sac.seismogram, update=update)
... seismograms.append(iccs_seismogram)
...
>>>
To better illustrate the different modes of running the ICCS algorithm, we modify the data and picks in the seismograms to make them worse than they actually are:
>>> from datetime import timedelta
>>> from copy import deepcopy
>>> import numpy as np
>>>
>>> # change the sign of the data in the first seismogram
>>> seismograms[0].data *= -1
>>>
>>> # move the initial pick 2 seconds earlier in second seismogram
>>> seismograms[1].t0 += timedelta(seconds=-2)
>>>
>>> # move the initial pick 2 seconds later in third seismogram
>>> seismograms[2].t0 += timedelta(seconds=2)
>>>
>>> # create a seismogram with completely random data
>>> iccs_random: MiniICCSSeismogram = deepcopy(seismograms[-1])
>>> np.random.seed(42) # set this for consistent results during testing
>>> iccs_random.data = np.random.rand(len(iccs_random))
>>> seismograms.append(iccs_random)
>>>
We can now create an instance of the ICCS
class
and plot the initial stack together with the input seismograms:
>>> from pysmo.tools.iccs import ICCS, plotstack
>>> iccs = ICCS(seismograms)
>>> plotstack(iccs, padded=False)
>>>
The phase emergance is not visible in the stack, and the (absolute) correlation coefficents of the the seismograms are not very high. This shows the initial picks are not very good and/or that the data are of low quality. To run the ICCS algorithm, we simply call (execute) the ICCS instance:
>>> convergence_list = iccs() # this runs the ICCS algorithm and returns
>>> # a list of the convergence value after each
>>> # iteration.
>>> plotstack(iccs, padded=False)
>>>


Despite of the random noise seismogram, the phase arrival is now visible in
the stack. Seismograms with low correlation coefficients can automatically
be deselected from the calculations by running ICCS again with
autoselect=True
:
>>> _ = iccs(autoselect=True)
>>> plotstack(iccs, padded=False)
>>>
Seismograms that fit better with their polarity reversed can be flipped
automatically by setting autoflip=True
:
>>> _ = iccs(autoflip=True)
>>> plotstack(iccs, padded=False)
>>>
To further improve results, you can interactively update the picks and
the time window using stack_pick
and
stack_tw_pick
, respectively, and
then run the ICCS algorithm again.
Methods:
-
__call__
–Run the iccs algorithm.
Attributes:
-
plot_padding
(timedelta
) –Padding to apply before and after the time window.
-
seismograms
(Sequence[ICCSSeismogram]
) –Input seismograms.
-
seismograms_ccnorm
(list[float]
) –Returns a list of the normalised cross-correlation coefficients.
-
seismograms_for_plotting
(list[MiniSeismogram]
) –Returns the windowed, detrended, normalised, and optionally flipped seismograms.
-
seismograms_prepared
(list[MiniSeismogram]
) –Returns the windowed, detrended, normalised, tapered, and optionally flipped seismograms.
-
stack
(MiniSeismogram
) –Returns the stacked seismograms (
seismograms_prepared
). -
stack_for_plotting
(MiniSeismogram
) –Returns the stacked seismograms (
seismograms_for_plotting
). -
taper_width
(timedelta | float
) –Taper width.
-
window_post
(timedelta
) –End of the time window relative to the pick.
-
window_pre
(timedelta
) –Begining of the time window relative to the pick.
Source code in pysmo/tools/iccs/_iccs.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 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 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
|
plot_padding
class-attribute
instance-attribute
#
plot_padding: timedelta = field(
default=timedelta(seconds=10),
validator=[
gt(timedelta(seconds=0)),
_clear_cache_on_update,
],
)
Padding to apply before and after the time window.
This padding is not used for the cross-correlation.
seismograms
class-attribute
instance-attribute
#
seismograms: Sequence[ICCSSeismogram] = field(
factory=lambda: list[ICCSSeismogram](),
validator=_clear_cache_on_update,
)
Input seismograms.
These seismograms provide the input data for ICCS. They are used to store
processing parameters and create shorter seismograms (based on pick and
time window) that are then used for cross-correlation. The shorter
seismograms are created on the fly and then cached within an ICCS
instance.
seismograms_ccnorm
property
#
Returns a list of the normalised cross-correlation coefficients.
seismograms_for_plotting
property
#
seismograms_for_plotting: list[MiniSeismogram]
Returns the windowed, detrended, normalised, and optionally flipped seismograms.
seismograms_prepared
property
#
seismograms_prepared: list[MiniSeismogram]
Returns the windowed, detrended, normalised, tapered, and optionally flipped seismograms.
stack
property
#
stack: MiniSeismogram
Returns the stacked seismograms (seismograms_prepared
).
The stack is calculated as the average of all seismograms with the
attribute select
set to
True
. The begin_time
of
the returned stack is the average of the begin_time
of the input seismograms.
Returns:
-
MiniSeismogram
–Stacked input seismograms.
stack_for_plotting
property
#
stack_for_plotting: MiniSeismogram
Returns the stacked seismograms (seismograms_for_plotting
).
Returns:
-
MiniSeismogram
–Stacked input seismograms.
taper_width
class-attribute
instance-attribute
#
Taper width.
Can be either a timedelta or a float - see pysmo.functions.taper()
for details.
window_post
class-attribute
instance-attribute
#
window_post: timedelta = field(
default=timedelta(seconds=10),
validator=[
gt(timedelta(seconds=0)),
_clear_cache_on_update,
],
)
End of the time window relative to the pick.
window_pre
class-attribute
instance-attribute
#
window_pre: timedelta = field(
default=timedelta(seconds=-10),
validator=[
lt(timedelta(seconds=0)),
_clear_cache_on_update,
],
)
Begining of the time window relative to the pick.
__call__
#
__call__(
autoflip: bool = False,
autoselect: bool = False,
convergence_limit: float = 1e-05,
convergence_method: CONVERGENCE_METHOD = "corrcoef",
max_iter: int = 10,
max_shift: timedelta | None = None,
min_ccnorm: float = 0.5,
parallel: bool = False,
) -> NDArray
Run the iccs algorithm.
Parameters:
-
autoflip
(bool
, default:False
) –Automatically toggle
flip
attribute of seismograms. -
autoselect
(bool
, default:False
) –Automatically set
select
attribute toFalse
for poor quality seismograms. -
convergence_limit
(float
, default:1e-05
) –Convergence limit at which the algorithm stops.
-
convergence_method
(CONVERGENCE_METHOD
, default:'corrcoef'
) –Method to calculate convergence criterion.
-
max_iter
(int
, default:10
) –Maximum number of iterations.
-
max_shift
(timedelta | None
, default:None
) –Maximum shift in seconds (see
delay()
). -
min_ccnorm
(float
, default:0.5
) –Minimum normalised cross-correlation coefficient. When
autoselect
isTrue
, seismograms with correlation coefficients below this value are set toselect=False
. -
parallel
(bool
, default:False
) –Whether to use parallel processing. Setting this to
True
will perform the cross-correlation calculations in parallel usingProcessPoolExecutor
. In most cases this will not be faster.
Returns:
-
convergence
(NDArray
) –Array of convergence criterion values.
Source code in pysmo/tools/iccs/_iccs.py
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 |
|
ICCSSeismogram
#
Bases: Seismogram
, Protocol
Protocol class to define the ICCSSeismogram
type.
The ICCSSeismogram
type extends the Seismogram
type
with the addition of parameters that are required for ICCS.
Methods:
-
__len__
–The length of the Seismogram.
Attributes:
-
begin_time
(datetime
) –Seismogram begin time.
-
data
(NDArray
) –Seismogram data.
-
delta
(timedelta
) –The sampling interval.
-
end_time
(datetime
) –Seismogram end time.
-
flip
(bool
) –Data in seismogram should be flipped for ICCS.
-
select
(bool
) –Use seismogram to create stack.
-
t0
(datetime
) –Initial pick.
-
t1
(datetime | None
) –Updated pick.
Source code in pysmo/tools/iccs/_types.py
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
|
MiniICCSSeismogram
#
Minimal implementation of the ICCSSeismogram
type.
The MiniICCSSeismogram
class provides
a minimal implementation of class that is compatible with the
ICCSSeismogram
.
Examples:
Because ICCSSeismogram
inherits
from Seismogram
, we can easily create
MiniICCSSeismogram
instances
from exisiting seismograms using the
clone_to_mini()
function, whereby
the update
parameter is used to provide the extra information needed:
>>> from pysmo.classes import SAC
>>> from pysmo.functions import clone_to_mini
>>> from pysmo.tools.iccs import MiniICCSSeismogram
>>> sac = SAC.from_file("example.sac")
>>> sac_seis = sac.seismogram
>>> update = {"t0": sac.timestamps.t0}
>>> mini_iccs_seis = clone_to_mini(MiniICCSSeismogram, sac_seis, update=update)
>>>
Methods:
-
__len__
–The length of the Seismogram.
Attributes:
-
begin_time
(datetime
) –Seismogram begin time.
-
data
(NDArray
) –Seismogram data.
-
delta
(timedelta
) –Seismogram sampling interval.
-
end_time
(datetime
) –Seismogram end time.
-
flip
(bool
) –Data in seismogram should be flipped for ICCS.
-
select
(bool
) –Use seismogram to create stack.
-
t0
(datetime
) –Initial pick.
-
t1
(datetime | None
) –Updated pick.
Source code in pysmo/tools/iccs/_types.py
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
|
begin_time
class-attribute
instance-attribute
#
begin_time: datetime = field(
default=begin_time.value, validator=datetime_is_utc
)
Seismogram begin time.
data
class-attribute
instance-attribute
#
Seismogram data.
delta
class-attribute
instance-attribute
#
Seismogram sampling interval.
flip
class-attribute
instance-attribute
#
flip: bool = False
Data in seismogram should be flipped for ICCS.
t0
class-attribute
instance-attribute
#
t0: datetime = field(validator=datetime_is_utc)
Initial pick.
t1
class-attribute
instance-attribute
#
t1: datetime | None = field(
default=None, validator=optional(datetime_is_utc)
)
Updated pick.
__len__
#
__len__() -> int
The length of the Seismogram.
Returns:
-
int
–Number of samples in the data array.
Source code in pysmo/tools/iccs/_types.py
107 108 109 110 111 112 113 |
|
plotstack
#
plotstack(
iccs: ICCS,
padded: bool = True,
return_fig: bool = False,
) -> tuple[Figure, Axes] | None
Plot the ICCS stack.
Parameters:
-
iccs
(ICCS
) –Instance of the
ICCS
class. -
padded
(bool
, default:True
) –If True, the plot is padded on both sides of the time window by the amount defined in
ICCS.plot_padding
. -
return_fig
(bool
, default:False
) –
Returns:
Examples:
The default plotting mode is to pad the stack beyond the time window used for the cross-correlations (highlighted in light green). This is useful particularly useful for narrow time windows. Note that because of the padding, the displayed stack isn't exactly what is used for the cross-correlations.
>>> from pysmo.tools.iccs import ICCS, plotstack
>>> iccs = ICCS(iccs_seismograms)
>>> _ = iccs(autoselect=True, autoflip=True)
>>>
>>> plotstack(iccs)
>>>
To view the stack exactly as it is used in the cross-correlations, set
the padded
argument to False
:
>>> plotstack(iccs, padded=False)
>>>
Source code in pysmo/tools/iccs/_functions.py
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
|
stack_pick
#
stack_pick(
iccs: ICCS,
padded: bool = True,
return_fig: bool = False,
) -> tuple[Figure, Axes] | None
Manually pick t1
in the stack and apply it to all seismograms.
This function launches an interactive figure to manually pick a new phase arrival in the stack, and then apply it to all seismograms.
Parameters:
-
iccs
(ICCS
) –Instance of the
ICCS
class. -
padded
(bool
, default:True
) –If True, the plot is padded on both sides of the time window by the amount defined in
ICCS.plot_padding
. -
return_fig
(bool
, default:False
) –
Returns:
Examples:
>>> from pysmo.tools.iccs import ICCS, stack_pick
>>> iccs = ICCS(iccs_seismograms)
>>> _ = iccs(autoselect=True, autoflip=True)
>>>
>>> stack_pick(iccs)
>>>
Source code in pysmo/tools/iccs/_functions.py
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 |
|
stack_tw_pick
#
stack_tw_pick(
iccs: ICCS,
padded: bool = True,
return_fig: bool = False,
) -> tuple[Figure, Axes] | None
Pick new time window limits in the stack.
This function launches an interactive figure to pick new values for
window_pre
and
window_post
.
Parameters:
-
iccs
(ICCS
) –Instance of the
ICCS
class. -
padded
(bool
, default:True
) –If True, the plot is padded on both sides of the time window by the amount defined in
ICCS.plot_padding
. -
return_fig
(bool
, default:False
) –
Returns:
Info
The new time window may not be chosen such that the pick lies outside the the window. The picker will therefore automatically correct itself for invalid window choices.
Examples:
>>> from pysmo.tools.iccs import ICCS, stack_tw_pick
>>> iccs = ICCS(iccs_seismograms)
>>> _ = iccs(autoselect=True, autoflip=True)
>>>
>>> stack_tw_pick(iccs)
>>>
Source code in pysmo/tools/iccs/_functions.py
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 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 |
|
update_pick
#
Update t1
in all seismograms by the same amount.
Parameters:
Source code in pysmo/tools/iccs/_functions.py
145 146 147 148 149 150 151 152 153 154 155 |
|