im-calculation 0.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- im_calculation-0.0.0/.gitignore +25 -0
- im_calculation-0.0.0/IM/__init__.py +0 -0
- im_calculation-0.0.0/IM/im_calculation.py +254 -0
- im_calculation-0.0.0/IM/im_reader.py +100 -0
- im_calculation-0.0.0/IM/ims.py +894 -0
- im_calculation-0.0.0/IM/ko_matrices.py +44 -0
- im_calculation-0.0.0/IM/scripts/calculate_ims.py +93 -0
- im_calculation-0.0.0/IM/scripts/gen_ko_matrix.py +56 -0
- im_calculation-0.0.0/IM/snr_calculation.py +143 -0
- im_calculation-0.0.0/IM/waveform_reading.py +104 -0
- im_calculation-0.0.0/MANIFEST.in +4 -0
- im_calculation-0.0.0/PKG-INFO +31 -0
- im_calculation-0.0.0/im_calculation.egg-info/PKG-INFO +31 -0
- im_calculation-0.0.0/im_calculation.egg-info/SOURCES.txt +18 -0
- im_calculation-0.0.0/im_calculation.egg-info/dependency_links.txt +1 -0
- im_calculation-0.0.0/im_calculation.egg-info/entry_points.txt +3 -0
- im_calculation-0.0.0/im_calculation.egg-info/requires.txt +28 -0
- im_calculation-0.0.0/im_calculation.egg-info/top_level.txt +4 -0
- im_calculation-0.0.0/pyproject.toml +83 -0
- im_calculation-0.0.0/setup.cfg +4 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
*.pyc
|
|
2
|
+
/IM/rspectra_calculations/rspectra.c
|
|
3
|
+
/IM/rspectra_calculations/rspectra.so
|
|
4
|
+
.idea
|
|
5
|
+
build/
|
|
6
|
+
test/test_calculate_ims/sample1/input/*.bin
|
|
7
|
+
test/test_calculate_ims/sample1/output/
|
|
8
|
+
test/test_calculate_ims/*.xml
|
|
9
|
+
test/test_calculate_ims/html*
|
|
10
|
+
test/test_calculate_ims/.coverage
|
|
11
|
+
test/test_calculate_ims/output/__pycache*
|
|
12
|
+
.cache/
|
|
13
|
+
*.sl
|
|
14
|
+
*.err
|
|
15
|
+
*.out
|
|
16
|
+
rrups.csv
|
|
17
|
+
.calculate_rrups.py.swp
|
|
18
|
+
*.log
|
|
19
|
+
runs/
|
|
20
|
+
**.so
|
|
21
|
+
**sample0
|
|
22
|
+
|
|
23
|
+
# special cases to unignore
|
|
24
|
+
!periods.out
|
|
25
|
+
.venv/
|
|
File without changes
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import multiprocessing
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from IM import ims
|
|
9
|
+
from IM.ims import IM
|
|
10
|
+
|
|
11
|
+
DEFAULT_PERIODS = np.asarray(
|
|
12
|
+
[
|
|
13
|
+
0.010,
|
|
14
|
+
0.020,
|
|
15
|
+
0.022,
|
|
16
|
+
0.025,
|
|
17
|
+
0.029,
|
|
18
|
+
0.030,
|
|
19
|
+
0.032,
|
|
20
|
+
0.035,
|
|
21
|
+
0.036,
|
|
22
|
+
0.040,
|
|
23
|
+
0.042,
|
|
24
|
+
0.044,
|
|
25
|
+
0.045,
|
|
26
|
+
0.046,
|
|
27
|
+
0.048,
|
|
28
|
+
0.050,
|
|
29
|
+
0.055,
|
|
30
|
+
0.060,
|
|
31
|
+
0.065,
|
|
32
|
+
0.067,
|
|
33
|
+
0.070,
|
|
34
|
+
0.075,
|
|
35
|
+
0.080,
|
|
36
|
+
0.085,
|
|
37
|
+
0.090,
|
|
38
|
+
0.095,
|
|
39
|
+
0.100,
|
|
40
|
+
0.110,
|
|
41
|
+
0.120,
|
|
42
|
+
0.130,
|
|
43
|
+
0.133,
|
|
44
|
+
0.140,
|
|
45
|
+
0.150,
|
|
46
|
+
0.160,
|
|
47
|
+
0.170,
|
|
48
|
+
0.180,
|
|
49
|
+
0.190,
|
|
50
|
+
0.200,
|
|
51
|
+
0.220,
|
|
52
|
+
0.240,
|
|
53
|
+
0.250,
|
|
54
|
+
0.260,
|
|
55
|
+
0.280,
|
|
56
|
+
0.290,
|
|
57
|
+
0.300,
|
|
58
|
+
0.320,
|
|
59
|
+
0.340,
|
|
60
|
+
0.350,
|
|
61
|
+
0.360,
|
|
62
|
+
0.380,
|
|
63
|
+
0.400,
|
|
64
|
+
0.420,
|
|
65
|
+
0.440,
|
|
66
|
+
0.450,
|
|
67
|
+
0.460,
|
|
68
|
+
0.480,
|
|
69
|
+
0.500,
|
|
70
|
+
0.550,
|
|
71
|
+
0.600,
|
|
72
|
+
0.650,
|
|
73
|
+
0.667,
|
|
74
|
+
0.700,
|
|
75
|
+
0.750,
|
|
76
|
+
0.800,
|
|
77
|
+
0.850,
|
|
78
|
+
0.900,
|
|
79
|
+
0.950,
|
|
80
|
+
1.000,
|
|
81
|
+
1.100,
|
|
82
|
+
1.200,
|
|
83
|
+
1.300,
|
|
84
|
+
1.400,
|
|
85
|
+
1.500,
|
|
86
|
+
1.600,
|
|
87
|
+
1.700,
|
|
88
|
+
1.800,
|
|
89
|
+
1.900,
|
|
90
|
+
2.000,
|
|
91
|
+
2.200,
|
|
92
|
+
2.400,
|
|
93
|
+
2.500,
|
|
94
|
+
2.600,
|
|
95
|
+
2.800,
|
|
96
|
+
3.000,
|
|
97
|
+
3.200,
|
|
98
|
+
3.400,
|
|
99
|
+
3.500,
|
|
100
|
+
3.600,
|
|
101
|
+
3.800,
|
|
102
|
+
4.000,
|
|
103
|
+
4.200,
|
|
104
|
+
4.400,
|
|
105
|
+
4.600,
|
|
106
|
+
4.800,
|
|
107
|
+
5.000,
|
|
108
|
+
5.500,
|
|
109
|
+
6.000,
|
|
110
|
+
6.500,
|
|
111
|
+
7.000,
|
|
112
|
+
7.500,
|
|
113
|
+
8.000,
|
|
114
|
+
8.500,
|
|
115
|
+
9.000,
|
|
116
|
+
9.500,
|
|
117
|
+
10.000,
|
|
118
|
+
11.000,
|
|
119
|
+
12.000,
|
|
120
|
+
13.000,
|
|
121
|
+
14.000,
|
|
122
|
+
15.000,
|
|
123
|
+
20.000,
|
|
124
|
+
]
|
|
125
|
+
)
|
|
126
|
+
DEFAULT_FREQUENCIES = np.logspace(
|
|
127
|
+
np.log10(0.01318257),
|
|
128
|
+
np.log10(100),
|
|
129
|
+
num=389,
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def calculate_ims(
|
|
134
|
+
waveform: np.ndarray,
|
|
135
|
+
dt: float,
|
|
136
|
+
ims_list: list[IM] = list(IM),
|
|
137
|
+
periods: np.ndarray = DEFAULT_PERIODS,
|
|
138
|
+
frequencies: np.ndarray = DEFAULT_FREQUENCIES,
|
|
139
|
+
cores: int = multiprocessing.cpu_count(),
|
|
140
|
+
ko_directory: Path | None = None,
|
|
141
|
+
use_numexpr: bool = False,
|
|
142
|
+
):
|
|
143
|
+
"""
|
|
144
|
+
Calculate intensity measures for a single waveform.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
waveform : np.ndarray
|
|
149
|
+
Waveform data as a NumPy array.
|
|
150
|
+
dt : float
|
|
151
|
+
Sampling interval (dt) of the waveform.
|
|
152
|
+
ims_list : list of IM, optional
|
|
153
|
+
List of intensity measures (IMs) to calculate, e.g., [IM.PGA, IM.pSA, IM.CAV].
|
|
154
|
+
periods : np.ndarray, optional
|
|
155
|
+
List of periods required for calculating the pseudo-spectral acceleration (pSA).
|
|
156
|
+
frequencies : np.ndarray, optional
|
|
157
|
+
List of frequencies required for calculating the Fourier amplitude spectrum (FAS).
|
|
158
|
+
cores : int, optional
|
|
159
|
+
Number of cores to use for parallel processing in pSA and FAS calculations.
|
|
160
|
+
ko_directory : Path, optional
|
|
161
|
+
Path to the directory containing the Konno-Ohmachi matrices.
|
|
162
|
+
Only required if FAS is in the list of IMs.
|
|
163
|
+
use_numexpr : bool, optional
|
|
164
|
+
If True, use numexpr for calculations. (Faster off for single waveform and multiprocessing)
|
|
165
|
+
Default is False.
|
|
166
|
+
|
|
167
|
+
Returns
|
|
168
|
+
-------
|
|
169
|
+
pd.DataFrame
|
|
170
|
+
DataFrame containing the calculated intensity measures.
|
|
171
|
+
The columns are the IMs and the rows are the different components.
|
|
172
|
+
|
|
173
|
+
Raises
|
|
174
|
+
------
|
|
175
|
+
ValueError
|
|
176
|
+
If the IM is not recognized or if required environment variables are not set to 1.
|
|
177
|
+
"""
|
|
178
|
+
if cores == 1:
|
|
179
|
+
required_env_vars = [
|
|
180
|
+
"NUMEXPR_NUM_THREADS",
|
|
181
|
+
"NUMBA_MAX_THREADS",
|
|
182
|
+
"NUMBA_NUM_THREADS",
|
|
183
|
+
"OPENBLAS_NUM_THREADS",
|
|
184
|
+
]
|
|
185
|
+
unset_vars = [var for var in required_env_vars if os.getenv(var) != "1"]
|
|
186
|
+
if unset_vars:
|
|
187
|
+
raise ValueError(
|
|
188
|
+
f"The following environment variables must be set to 1: {', '.join(unset_vars)}"
|
|
189
|
+
)
|
|
190
|
+
if ko_directory is None and IM.FAS in ims_list:
|
|
191
|
+
raise ValueError(
|
|
192
|
+
"The Konno-Ohmachi directory must be provided if Fourier amplitude spectrum is in the list of IMs."
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
results = []
|
|
196
|
+
|
|
197
|
+
# Iterate through IMs and calculate them
|
|
198
|
+
for im in ims_list:
|
|
199
|
+
if im == IM.PGA:
|
|
200
|
+
result = ims.peak_ground_acceleration(waveform, use_numexpr=use_numexpr)
|
|
201
|
+
result.index = [im.value]
|
|
202
|
+
elif im == IM.PGV:
|
|
203
|
+
result = ims.peak_ground_velocity(waveform, dt, use_numexpr=use_numexpr)
|
|
204
|
+
result.index = [im.value]
|
|
205
|
+
elif im == IM.pSA:
|
|
206
|
+
data_array = ims.pseudo_spectral_acceleration(
|
|
207
|
+
waveform, periods, np.float32(dt), cores=cores, use_numexpr=use_numexpr
|
|
208
|
+
)
|
|
209
|
+
# Convert the data array to a DataFrame
|
|
210
|
+
result = data_array.to_dataframe().unstack(level="component")
|
|
211
|
+
result.index = [
|
|
212
|
+
f"{im.value}_{idx}" for idx in data_array.coords["period"].values
|
|
213
|
+
]
|
|
214
|
+
result.columns = result.columns.droplevel(0)
|
|
215
|
+
elif im == IM.CAV:
|
|
216
|
+
result = ims.cumulative_absolute_velocity(waveform, dt)
|
|
217
|
+
result.index = [im.value]
|
|
218
|
+
elif im == IM.CAV5:
|
|
219
|
+
result = ims.cumulative_absolute_velocity(waveform, dt, 5)
|
|
220
|
+
result.index = [im.value]
|
|
221
|
+
elif im == IM.Ds575:
|
|
222
|
+
result = ims.ds575(waveform, dt, use_numexpr=use_numexpr)
|
|
223
|
+
result.index = [im.value]
|
|
224
|
+
elif im == IM.Ds595:
|
|
225
|
+
result = ims.ds595(waveform, dt, use_numexpr=use_numexpr)
|
|
226
|
+
result.index = [im.value]
|
|
227
|
+
elif im == IM.AI:
|
|
228
|
+
result = ims.arias_intensity(waveform, dt)
|
|
229
|
+
result.index = [im.value]
|
|
230
|
+
elif im == IM.FAS:
|
|
231
|
+
assert ko_directory
|
|
232
|
+
data_array = ims.fourier_amplitude_spectra(
|
|
233
|
+
waveform,
|
|
234
|
+
dt,
|
|
235
|
+
frequencies,
|
|
236
|
+
cores=cores,
|
|
237
|
+
# ko_directory must be Path because of the check earlier.
|
|
238
|
+
ko_directory=ko_directory,
|
|
239
|
+
)
|
|
240
|
+
# Convert the data array to a DataFrame
|
|
241
|
+
result = data_array.to_dataframe().unstack(level="component")
|
|
242
|
+
result.index = [
|
|
243
|
+
f"{im.value}_{idx}" for idx in data_array.coords["frequency"].values
|
|
244
|
+
]
|
|
245
|
+
result.columns = result.columns.droplevel(0)
|
|
246
|
+
else:
|
|
247
|
+
raise ValueError(
|
|
248
|
+
f"IM {im} not recognized. Available IMs are {IM.__members__.keys()}"
|
|
249
|
+
)
|
|
250
|
+
results.append(result)
|
|
251
|
+
|
|
252
|
+
# Combine all results into a single DataFrame
|
|
253
|
+
output_ims = pd.concat(results).T
|
|
254
|
+
return output_ims
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
|
|
3
|
+
# Importing pint_xarray registers pint units with xarray, allowing for
|
|
4
|
+
# unit-aware operations. It is not explicitly used, so we ignore the flake8
|
|
5
|
+
# F401 error.
|
|
6
|
+
import pint_xarray # noqa: F401
|
|
7
|
+
import xarray as xr
|
|
8
|
+
|
|
9
|
+
from IM.ims import IM
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def read_intensity_measures(
|
|
13
|
+
intensity_measure_file: str | Path,
|
|
14
|
+
) -> xr.Dataset:
|
|
15
|
+
"""
|
|
16
|
+
Read intensity measures from a file and return as an xarray Dataset.
|
|
17
|
+
|
|
18
|
+
Parameters
|
|
19
|
+
----------
|
|
20
|
+
intensity_measure_file : str or Path
|
|
21
|
+
The file path or filename of the intensity measures dataset to be read.
|
|
22
|
+
|
|
23
|
+
Returns
|
|
24
|
+
-------
|
|
25
|
+
xr.Dataset
|
|
26
|
+
The xarray dataset containing the intensity measures."""
|
|
27
|
+
return xr.open_dataset(intensity_measure_file, engine="h5netcdf").pint.quantify()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
COORDINATE_METADATA = {
|
|
31
|
+
"station": {"description": "Station identifiers", "units": None},
|
|
32
|
+
"component": {"description": "Component of motion", "units": None},
|
|
33
|
+
"period": {"description": "Oscillation period", "units": "s"},
|
|
34
|
+
"vs30": {
|
|
35
|
+
"description": "Average shear-wave velocity to 30m depth",
|
|
36
|
+
"units": "m/s",
|
|
37
|
+
},
|
|
38
|
+
"epi": {"description": "Epicentral distance", "units": "km"},
|
|
39
|
+
"hyp": {"description": "Hypocentral distance", "units": "km"},
|
|
40
|
+
"rrup": {"description": "Rupture distance", "units": "km"},
|
|
41
|
+
"rjb": {"description": "Joyner-Boore distance", "units": "km"},
|
|
42
|
+
"latitude": {"description": "Station latitude", "units": "degrees"},
|
|
43
|
+
"longitude": {"description": "Station longitude", "units": "degrees"},
|
|
44
|
+
"frequency": {"description": "Frequency of motion", "units": "Hz"},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
IM_METADATA = {
|
|
48
|
+
IM.PGA: "Peak ground acceleration",
|
|
49
|
+
IM.PGV: "Peak ground velocity",
|
|
50
|
+
IM.CAV: "Cumulative absolute velocity",
|
|
51
|
+
IM.CAV5: "Cumulative absolute velocity (above 5 cm/s)",
|
|
52
|
+
IM.AI: "Arias intensity",
|
|
53
|
+
IM.Ds575: "Significant duration (5-75%)",
|
|
54
|
+
IM.Ds595: "Significant duration (5-95%)",
|
|
55
|
+
IM.pSA: "Pseudo-spectral acceleration",
|
|
56
|
+
IM.FAS: "Fourier amplitude spectrum",
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# The 'g0' unit is used for acceleration and is equivalent to 9.81 m/s^2. The
|
|
61
|
+
# reason for this is that 'g' is reserved for 'grams'. This is a decision
|
|
62
|
+
# made by the `pint` library, which is used to handle the units.
|
|
63
|
+
IM_UNITS = {
|
|
64
|
+
IM.PGA: "g0",
|
|
65
|
+
IM.PGV: "cm/s",
|
|
66
|
+
IM.CAV: "m/s",
|
|
67
|
+
IM.CAV5: "m/s",
|
|
68
|
+
IM.AI: "m/s",
|
|
69
|
+
IM.Ds575: "s",
|
|
70
|
+
IM.Ds595: "s",
|
|
71
|
+
IM.FAS: "g0 * s",
|
|
72
|
+
IM.pSA: "g0",
|
|
73
|
+
"frequency": "Hz",
|
|
74
|
+
"period": "s",
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def write_intensity_measures(dataset: xr.Dataset, output_ffp: str | Path) -> None:
|
|
79
|
+
"""Write intensity measures to a file, updating coordinate and variable metadata.
|
|
80
|
+
|
|
81
|
+
Parameters
|
|
82
|
+
----------
|
|
83
|
+
dataset : xr.Dataset
|
|
84
|
+
The xarray dataset containing intensity measures to be written.
|
|
85
|
+
output_ffp : str or Path
|
|
86
|
+
The file path where the output dataset should be saved.
|
|
87
|
+
"""
|
|
88
|
+
for name, description in COORDINATE_METADATA.items():
|
|
89
|
+
if name not in dataset.coords:
|
|
90
|
+
continue
|
|
91
|
+
dataset.coords[name].attrs.update(COORDINATE_METADATA[name])
|
|
92
|
+
|
|
93
|
+
for im_name, description in IM_METADATA.items():
|
|
94
|
+
if im_name not in dataset:
|
|
95
|
+
continue
|
|
96
|
+
dataset[im_name].attrs["description"] = IM_METADATA[im_name]
|
|
97
|
+
|
|
98
|
+
dataset = dataset.pint.quantify(IM_UNITS)
|
|
99
|
+
|
|
100
|
+
dataset.pint.dequantify().to_netcdf(output_ffp, engine="h5netcdf")
|