Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: change freq_norm from string to enum #248

Merged
merged 17 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 6 additions & 5 deletions script/test_whiten.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import scipy
from scipy.fftpack import next_fast_len

from noisepy.seis.datatypes import FreqNorm
from noisepy.seis.noise_module import moving_ave, whiten


Expand Down Expand Up @@ -62,9 +63,9 @@ def whiten_original(data, fft_para):
1j * np.angle(FFTRawSign[:, low:left])
)
# Pass band:
if freq_norm == "phase_only":
if freq_norm == FreqNorm.PHASE_ONLY:
FFTRawSign[:, left:right] = np.exp(1j * np.angle(FFTRawSign[:, left:right]))
elif freq_norm == "rma":
elif freq_norm == FreqNorm.RMA:
for ii in range(data.shape[0]):
tave = moving_ave(np.abs(FFTRawSign[ii, left:right]), smooth_N)
FFTRawSign[ii, left:right] = FFTRawSign[ii, left:right] / tave
Expand All @@ -82,9 +83,9 @@ def whiten_original(data, fft_para):
1j * np.angle(FFTRawSign[low:left])
)
# Pass band:
if freq_norm == "phase_only":
if freq_norm == FreqNorm.PHASE_ONLY:
FFTRawSign[left:right] = np.exp(1j * np.angle(FFTRawSign[left:right]))
elif freq_norm == "rma":
elif freq_norm == FreqNorm.RMA:
tave = moving_ave(np.abs(FFTRawSign[left:right]), smooth_N)
FFTRawSign[left:right] = FFTRawSign[left:right] / tave
# Right tapering:
Expand All @@ -109,7 +110,7 @@ def whiten_original(data, fft_para):
"freqmin": 0.01,
"freqmax": 0.2,
"smooth_N": 1,
"freq_norm": "phase_only",
"freq_norm": FreqNorm.PHASE_ONLY,
}

# 1 D case
Expand Down
10 changes: 8 additions & 2 deletions src/noisepy/seis/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,12 @@ class StackMethod(Enum):
ALL = "all"


class FreqNorm(Enum):
RMA = "rma"
NO = "no"
PHASE_ONLY = "phase_only"


class ConfigParameters(BaseModel):
model_config = ConfigDict(validate_default=True)

Expand Down Expand Up @@ -138,8 +144,8 @@ class ConfigParameters(BaseModel):
step: float = Field(default=450.0, description="overlapping between each cc_len (sec)")
freqmin: float = Field(default=0.05)
freqmax: float = Field(default=2.0)
freq_norm: str = Field(
default="rma", description="choose between 'rma' for a soft whitenning or 'no' for no whitening"
freq_norm: FreqNorm = Field(
default=FreqNorm.RMA.value, description="choose between 'rma' for a soft whitenning or 'no' for no whitening"
)
# TODO: change "no"for "None", and add "one_bit"as an option
# TODO: change time_norm option from "no"to "None"
Expand Down
4 changes: 2 additions & 2 deletions src/noisepy/seis/noise_module.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from scipy.fftpack import next_fast_len
from scipy.signal import hilbert

from .datatypes import ChannelData, ConfigParameters, StackMethod
from .datatypes import ChannelData, ConfigParameters, FreqNorm, StackMethod

logger = logging.getLogger(__name__)
"""
Expand Down Expand Up @@ -559,7 +559,7 @@ def noise_processing(fft_para: ConfigParameters, dataS):
white = dataS

# -----to whiten or not------
if fft_para.freq_norm != "no":
if fft_para.freq_norm != FreqNorm.NO:
source_white = whiten(white, fft_para) # whiten and return FFT
else:
Nfft = int(next_fast_len(int(dataS.shape[1])))
Expand Down
45 changes: 28 additions & 17 deletions tests/test_whiten.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import matplotlib.pyplot as plt
import numpy as np
import pytest
import scipy
from scipy.fftpack import next_fast_len

from noisepy.seis.correlate import ConfigParameters
from noisepy.seis.datatypes import FreqNorm
from noisepy.seis.noise_module import moving_ave, whiten


Expand Down Expand Up @@ -56,9 +58,9 @@ def whiten_original(data, fft_para: ConfigParameters):
1j * np.angle(FFTRawSign[:, low:left])
)
# Pass band:
if fft_para.freq_norm == "phase_only":
if fft_para.freq_norm == FreqNorm.PHASE_ONLY:
FFTRawSign[:, left:right] = np.exp(1j * np.angle(FFTRawSign[:, left:right]))
elif fft_para.freq_norm == "rma":
elif fft_para.freq_norm == FreqNorm.RMA:
for ii in range(data.shape[0]):
tave = moving_ave(np.abs(FFTRawSign[ii, left:right]), fft_para.smooth_N)
FFTRawSign[ii, left:right] = FFTRawSign[ii, left:right] / tave
Expand All @@ -76,9 +78,9 @@ def whiten_original(data, fft_para: ConfigParameters):
1j * np.angle(FFTRawSign[low:left])
)
# Pass band:
if fft_para.freq_norm == "phase_only":
if fft_para.freq_norm == FreqNorm.PHASE_ONLY:
FFTRawSign[left:right] = np.exp(1j * np.angle(FFTRawSign[left:right]))
elif fft_para.freq_norm == "rma":
elif fft_para.freq_norm == FreqNorm.RMA:
tave = moving_ave(np.abs(FFTRawSign[left:right]), fft_para.smooth_N)
FFTRawSign[left:right] = FFTRawSign[left:right] / tave
# Right tapering:
Expand All @@ -98,16 +100,16 @@ def whiten_original(data, fft_para: ConfigParameters):
# it is not expected that the smoothed version returns the same, so currently no test for that
# (would be good to add one based on some expected outcome)

fft_para = ConfigParameters()
fft_para.samp_freq = 1.0
fft_para.freqmin = 0.01
fft_para.freqmax = 0.2
fft_para.smooth_N = 1
fft_para.freq_norm = "phase_only"


def whiten1d():
def whiten1d(freq_norm: FreqNorm):
# 1 D case
fft_para = ConfigParameters()
fft_para.samp_freq = 1.0
fft_para.freqmin = 0.01
fft_para.freqmax = 0.2
fft_para.smooth_N = 1
fft_para.freq_norm = freq_norm

data = np.random.random(1000)
white_original = whiten_original(data, fft_para)
white_new = whiten(data, fft_para)
Expand All @@ -118,8 +120,15 @@ def whiten1d():
return white_original, white_new


def whiten2d():
def whiten2d(freq_norm: FreqNorm):
# 2 D case
fft_para = ConfigParameters()
fft_para.samp_freq = 1.0
fft_para.freqmin = 0.01
fft_para.freqmax = 0.2
fft_para.smooth_N = 1
fft_para.freq_norm = freq_norm

data = np.random.random((5, 1000))
white_original = whiten_original(data, fft_para)
white_new = whiten(data, fft_para)
Expand Down Expand Up @@ -157,12 +166,14 @@ def plot_2d(white_original, white_new):


# Use wrappers since test functions are not supposed to return values
def test_whiten1d():
_, _ = whiten1d()
@pytest.mark.parametrize("freqNorm", [FreqNorm.PHASE_ONLY, FreqNorm.RMA])
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very nice! And I see that the code coverage check is now passing.

def test_whiten1d(freqNorm: FreqNorm):
_, _ = whiten1d(freqNorm)


def test_whiten2d():
_, _ = whiten2d()
@pytest.mark.parametrize("freqNorm", [FreqNorm.PHASE_ONLY, FreqNorm.RMA])
def test_whiten2d(freqNorm: FreqNorm):
_, _ = whiten2d(freqNorm)


if __name__ == "__main__":
Expand Down
7 changes: 7 additions & 0 deletions tutorials/_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,10 @@ repository:
html:
use_issues_button: true
use_repository_button: true

# Set navigation_with_keys: false to prevent pydata-sphinx-theme validation warning/error
# See https://github.com/pydata/pydata-sphinx-theme/issues/1492
sphinx:
config:
html_theme_options:
navigation_with_keys: false
6 changes: 3 additions & 3 deletions tutorials/get_started.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"source": [
"from noisepy.seis import download, cross_correlate, stack, plotting_modules, __version__\n",
"from noisepy.seis.asdfstore import ASDFRawDataStore, ASDFCCStore, ASDFStackStore\n",
"from noisepy.seis.datatypes import ConfigParameters\n",
"from noisepy.seis.datatypes import ConfigParameters, FreqNorm\n",
"from dateutil.parser import isoparse\n",
"import os\n",
"print(f\"Using NoisePy version {__version__}\")\n",
Expand Down Expand Up @@ -119,7 +119,7 @@
"config.max_over_std = 10 # threshold to remove window of bad signals: set it to 10*9 if prefer not to remove them\n",
"\n",
"# TEMPORAL and SPECTRAL NORMALISATION\n",
"config.freq_norm= \"rma\" # choose between \"rma\" for a soft whitenning or \"no\" for no whitening. Pure whitening is not implemented correctly at this point.\n",
"config.freq_norm= FreqNorm.RMA # choose between \"rma\" for a soft whitenning or \"no\" for no whitening. Pure whitening is not implemented correctly at this point.\n",
"config.smoothspect_N = 10 # moving window length to smooth spectrum amplitude (points)\n",
" # here, choose smoothspect_N for the case of a strict whitening (e.g., phase_only)\n",
"\n",
Expand Down Expand Up @@ -248,7 +248,7 @@
},
"outputs": [],
"source": [
"config.freq_norm = \"rma\"\n",
"config.freq_norm = FreqNorm.RMA\n",
"raw_store = ASDFRawDataStore(raw_data_path) # Store for reading raw data\n",
"cc_store = ASDFCCStore(cc_data_path) # Store for writing CC data\n",
"\n",
Expand Down
4 changes: 2 additions & 2 deletions tutorials/noisepy_pnwstore_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@
"from noisepy.seis.asdfstore import ASDFCCStore, ASDFStackStore # Object to store ASDF data within noisepy\n",
"from noisepy.seis.scedc_s3store import channel_filter\n",
"from noisepy.seis.pnwstore import PNWDataStore\n",
"from noisepy.seis.datatypes import ConfigParameters, Channel, ChannelData, ChannelType, Station # Main configuration object\n",
"from noisepy.seis.datatypes import ConfigParameters, Channel, ChannelData, ChannelType, FreqNorm, Station # Main configuration object\n",
"from noisepy.seis.channelcatalog import XMLStationChannelCatalog # Required stationXML handling object\n",
"import os\n",
"from datetime import datetime\n",
Expand Down Expand Up @@ -185,7 +185,7 @@
"config.max_over_std = 10 # threshold to remove window of bad signals: set it to 10*9 if prefer not to remove them\n",
"\n",
"# TEMPORAL and SPECTRAL NORMALISATION\n",
"config.freq_norm= \"rma\" # choose between \"rma\" for a soft whitenning or \"no\" for no whitening. Pure whitening is not implemented correctly at this point.\n",
"config.freq_norm= FreqNorm.RMA # choose between \"rma\" for a soft whitenning or \"no\" for no whitening. Pure whitening is not implemented correctly at this point.\n",
"config.smoothspect_N = 10 # moving window length to smooth spectrum amplitude (points)\n",
" # here, choose smoothspect_N for the case of a strict whitening (e.g., phase_only)\n",
"\n",
Expand Down
4 changes: 2 additions & 2 deletions tutorials/noisepy_scedc_tutorial.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
"from noisepy.seis import cross_correlate, stack, plotting_modules, __version__ # noisepy core functions\n",
"from noisepy.seis.asdfstore import ASDFCCStore, ASDFStackStore # Object to store ASDF data within noisepy\n",
"from noisepy.seis.scedc_s3store import SCEDCS3DataStore, channel_filter # Object to query SCEDC data from on S3\n",
"from noisepy.seis.datatypes import ConfigParameters, StackMethod # Main configuration object\n",
"from noisepy.seis.datatypes import ConfigParameters, FreqNorm, StackMethod # Main configuration object\n",
"from noisepy.seis.channelcatalog import XMLStationChannelCatalog # Required stationXML handling object\n",
"import os\n",
"from datetime import datetime\n",
Expand Down Expand Up @@ -201,7 +201,7 @@
"config.max_over_std = 10 # threshold to remove window of bad signals: set it to 10*9 if prefer not to remove them\n",
"\n",
"################### SPECTRAL NORMALIZATION ############\n",
"config.freq_norm= \"rma\" # choose between \"rma\" for a soft whitening or \"no\" for no whitening. Pure whitening is not implemented correctly at this point.\n",
"config.freq_norm= FreqNorm.RMA # choose between \"rma\" for a soft whitening or \"no\" for no whitening. Pure whitening is not implemented correctly at this point.\n",
"config.smoothspect_N = 10 # moving window length to smooth spectrum amplitude (points)\n",
" # here, choose smoothspect_N for the case of a strict whitening (e.g., phase_only)\n",
"\n",
Expand Down
3 changes: 2 additions & 1 deletion tutorials/old/cross_correlation_from_sac.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"import matplotlib.pyplot as plt \n",
"\n",
"sys.path.insert(1,'../src')\n",
"from noisepy.seis.datatypes import FreqNorm\n",
"from noisepy.seis import noise_module"
]
},
Expand Down Expand Up @@ -105,7 +106,7 @@
"freqmin = 0.1 # frequency range\n",
"freqmax = 8 \n",
"\n",
"freq_norm = 'rma' # rma-> running mean average for frequency-domain normalization\n",
"freq_norm = FreqNorm.RMA # rma-> running mean average for frequency-domain normalization\n",
"time_norm = 'no' # no-> no time-domain normalization; other options are 'rma' for running-mean and 'one-bit'\n",
"cc_method = 'xcorr' # xcorr-> pure cross correlation; other option is 'decon'\n",
"substack = False # sub-stack daily cross-correlation or not\n",
Expand Down
4 changes: 3 additions & 1 deletion tutorials/old/download_toASDF_cross_correlation.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,10 @@
"import pandas as pd\n",
"from obspy import UTCDateTime\n",
"import matplotlib.pyplot as plt\n",
"from noisepy.seis.datatypes import FreqNorm\n",
"from obspy.clients.fdsn import Client\n",
"\n",
"\n",
"sys.path.insert(1,'../src')\n",
"import noise_module"
]
Expand Down Expand Up @@ -206,7 +208,7 @@
"dt = 1/samp_freq # sampling time intervals of the data: in real case it reads from data directly\n",
"inc_hours = 24 # basic length (hour) of the continous noise data \n",
"\n",
"freq_norm = 'rma' # rma-> running mean average for frequency-domain normalization\n",
"freq_norm = FreqNorm.RMA # rma-> running mean average for frequency-domain normalization\n",
"time_norm = 'no' # no-> no time-domain normalization; other options are 'rma' for running-mean and 'one-bit'\n",
"cc_method = 'xcorr' # xcorr-> pure cross correlation; other option is 'decon'\n",
"substack = False # sub-stack daily cross-correlation or not\n",
Expand Down
4 changes: 2 additions & 2 deletions tutorials/run_mpi_scedc.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"from noisepy.seis import cross_correlate, stack, plotting_modules # noisepy core functions\n",
"from noisepy.seis.asdfstore import ASDFCCStore # Object to store ASDF data within noisepy\n",
"from noisepy.seis.scedc_s3store import SCEDCS3DataStore, channel_filter # Object to query SCEDC data from on S3\n",
"from noisepy.seis.datatypes import ConfigParameters # Main configuration object\n",
"from noisepy.seis.datatypes import ConfigParameters, FreqNorm # Main configuration object\n",
"from noisepy.seis.channelcatalog import XMLStationChannelCatalog # Required stationXML handling object\n",
"import os\n",
"import glob\n",
Expand All @@ -27,7 +27,7 @@
"stack_data_path = os.path.join(path, \"STACK\")\n",
"os.makedirs(cc_data_path, exist_ok=True)\n",
"os.makedirs(stack_data_path, exist_ok=True)\n",
"freq_norm=\"rma\"\n",
"freq_norm = FreqNorm.RMA\n",
"cc_store = ASDFCCStore(cc_data_path) # Store for writing CC data\n",
"\n",
"\n",
Expand Down
Loading