Skip to content

Commit 7d37bad

Browse files
authored
Create CI/CD pipeline; various config/style updates
* Create python-package.yml * Move dependencies to requirements.txt * Install library; add py 3.6 & 3.7 * Update flake8 command * Only run flake8 within ./PySeismoSoil * Fix style in all .py files * Fix over-indenting issue * Stop ignoring E117 * Fix invalid escape sequence in string * Update linting bash script * Add testing bash script * Add contributing instructions * Small tweaks in style * Add python-publish.yml * Update doc & readme * Update code styles in examples; fix some code * Update sed command per https://stackoverflow.com/a/19457213 * v0.4.1 -> v0.4.2 * Move unit test folder to root folder
1 parent 455be0f commit 7d37bad

File tree

76 files changed

+923
-679
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

76 files changed

+923
-679
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
2+
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
3+
4+
name: Python package
5+
6+
on:
7+
push:
8+
branches: [ "master" ]
9+
pull_request:
10+
branches: [ "master" ]
11+
12+
jobs:
13+
build:
14+
15+
runs-on: ubuntu-latest
16+
strategy:
17+
fail-fast: false
18+
matrix:
19+
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
20+
21+
steps:
22+
- uses: actions/checkout@v3
23+
- name: Set up Python ${{ matrix.python-version }}
24+
uses: actions/setup-python@v3
25+
with:
26+
python-version: ${{ matrix.python-version }}
27+
- name: Install dependencies
28+
run: |
29+
python -m pip install --upgrade pip
30+
python -m pip install flake8 pytest
31+
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
32+
python -m pip install -e .
33+
- name: Lint with flake8
34+
run: |
35+
flake8 ./PySeismoSoil --count --statistics --ignore=C901,E203,E741,E221,W605,E502,E116,W504,E266,E114,E222 --max-line-length=99 --max-complexity=10
36+
- name: Test with pytest
37+
run: |
38+
pytest
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# This workflow will upload a Python Package using Twine when a release is created
2+
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
3+
4+
# This workflow uses actions that are not certified by GitHub.
5+
# They are provided by a third-party and are governed by
6+
# separate terms of service, privacy policy, and support
7+
# documentation.
8+
9+
name: Upload Python Package
10+
11+
on:
12+
release:
13+
types: [published]
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
deploy:
20+
21+
runs-on: ubuntu-latest
22+
23+
steps:
24+
- uses: actions/checkout@v3
25+
- name: Set up Python
26+
uses: actions/setup-python@v3
27+
with:
28+
python-version: '3.x'
29+
- name: Install dependencies
30+
run: |
31+
python -m pip install --upgrade pip
32+
pip install build
33+
- name: Build package
34+
run: python -m build
35+
- name: Publish package
36+
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
37+
with:
38+
user: __token__
39+
password: ${{ secrets.PYPI_API_TOKEN }}

CONTRIBUTING.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Contributing Instructions
2+
3+
- In general, contributors should make code changes on a branch, and then [create a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) to have the changes merged
4+
- It is strongly recommended that contributors work on code changes in an isolated Python environment
5+
+ Use `pip install -e .` to install this library locally, so that any local code changes are reflected immediately in your current Python environment
6+
- To make sure your code style is compliant, run `./run_linting.sh` locally on your computer to check style violations
7+
+ You might want to run `chmod +x run_linting.sh` to make `run_linting.sh` executable
8+
- Please also run all unit tests by running `./run_tests.sh` before committing code to GitHub
9+
+ You might want to run `chmod +x run_tests.sh` to make `run_tests.sh` executable
10+
- Even if you don't run unit tests and check code styles locally, unit tests and code styles are checked on every push at GitHub

PySeismoSoil/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# Author: Jian Shi
22

3-
__version__ = 'v0.4.1'
3+
__version__ = 'v0.4.2'

PySeismoSoil/class_Vs_profile.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
from .class_frequency_spectrum import Frequency_Spectrum
88

9+
910
class Vs_Profile:
1011
"""
1112
Class implementation of a Vs profile
@@ -100,9 +101,9 @@ def __init__(
100101
if n_col == 2:
101102
xi, rho = sr.get_xi_rho(vs, formula_type=xi_rho_formula)
102103
if thk[-1] == 0: # last layer is an "infinity" layer
103-
material_number = np.append(np.arange(1, n_layer_tmp),[0])
104+
material_number = np.append(np.arange(1, n_layer_tmp), [0])
104105
else:
105-
material_number = np.arange(1, n_layer_tmp+1)
106+
material_number = np.arange(1, n_layer_tmp + 1)
106107
full_data = np.column_stack((thk, vs, xi, rho, material_number))
107108
elif n_col == 5:
108109
xi = data_[:, 2]
@@ -169,7 +170,7 @@ def __repr__(self):
169170
for j in range(n_layer_all):
170171
text += '{:^10}|'.format('%.2f' % self.vs_profile[j, 0])
171172
text += '{:^10}|'.format('%.1f' % self.vs_profile[j, 1])
172-
text += '{:^13}|'.format('%.3f' % (self.vs_profile[j, 2]*100.0))
173+
text += '{:^13}|'.format('%.3f' % (self.vs_profile[j, 2] * 100.0))
173174
text += '{:^18}|'.format('%.1f' % self.vs_profile[j, 3])
174175
text += '{:^14}'.format('%d' % self.vs_profile[j, 4])
175176
text += '\n'

PySeismoSoil/class_frequency_spectrum.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,12 @@ def plot(
162162
ax.set_xlabel('Frequency [Hz]')
163163
ax.set_ylabel('Amplitude or phase')
164164
ax.grid(ls=':')
165-
if logx: ax.set_xscale('log')
166-
if logy: ax.set_yscale('log')
167-
if self._file_name: ax.set_title(self._file_name)
165+
if logx:
166+
ax.set_xscale('log')
167+
if logy:
168+
ax.set_yscale('log')
169+
if self._file_name:
170+
ax.set_title(self._file_name)
168171

169172
return fig, ax
170173

PySeismoSoil/class_ground_motion.py

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from PySeismoSoil.class_frequency_spectrum import Frequency_Spectrum as FS
1010
from PySeismoSoil.class_Vs_profile import Vs_Profile
1111

12+
1213
class Ground_Motion:
1314
"""
1415
Class implementation of an earthquake ground motion.
@@ -114,7 +115,7 @@ def __init__(
114115

115116
self.dt = float(dt) # float; unit: sec
116117
self.npts = len(data_[:, 0]) # int; how many time points
117-
self.time = np.linspace(0, self.dt*(self.npts-1), num=self.npts)
118+
self.time = np.linspace(0, self.dt * (self.npts - 1), num=self.npts)
118119

119120
if motion_type == 'accel':
120121
self.accel = data_ # numpy array, with length unit 'm'
@@ -235,7 +236,7 @@ def get_response_spectra(
235236
)
236237
return rs
237238

238-
def plot(self, show_as_unit='m', fig=None, ax=None, figsize=(5,6), dpi=100):
239+
def plot(self, show_as_unit='m', fig=None, ax=None, figsize=(5, 6), dpi=100):
239240
"""
240241
Plots acceleration, velocity, and displacement waveforms together.
241242
@@ -382,13 +383,13 @@ def __calc_Arias(self, motion='accel', show_fig=False):
382383
Ia_1col = np.zeros(n)
383384
a_sq = a ** 2.0
384385

385-
for i in range(1,n):
386+
for i in range(1, n):
386387
Ia_1col[i] = Ia_1col[i - 1] + np.pi / (2 * g) * a_sq[i - 1] * dt
387388

388389
Ia_peak = float(Ia_1col[-1])
389-
Ia = np.column_stack((t,Ia_1col))
390+
Ia = np.column_stack((t, Ia_1col))
390391
Ia_norm_1col = Ia_1col / Ia_peak # normalized
391-
Ia_norm = np.column_stack((t,Ia_norm_1col))
392+
Ia_norm = np.column_stack((t, Ia_norm_1col))
392393

393394
t_low, t_high = self.__arias_time_bounds(t, Ia_norm_1col, 0.05, 0.95)
394395
T5_95 = t_high - t_low
@@ -426,7 +427,7 @@ def scale_motion(self, factor=1.0, target_PGA_in_g=None):
426427
scaled_motion : Ground_Motion
427428
The scaled motion
428429
"""
429-
if target_PGA_in_g != None:
430+
if target_PGA_in_g is not None:
430431
factor = target_PGA_in_g / self.pga_in_g
431432
else: # factor != None, and target_PGA_in_g is None
432433
pass
@@ -495,34 +496,36 @@ def truncate(self, limit, arias=True, extend=[0, 0], show_fig=False):
495496
n1 = int(t1 / self.dt)
496497
n2 = int(t2 / self.dt)
497498

498-
if n1 < 0: n1 = 0
499-
if n2 > self.npts: n2 = self.npts
499+
if n1 < 0:
500+
n1 = 0
501+
if n2 > self.npts:
502+
n2 = self.npts
500503

501-
time_trunc = self.accel[:n2-n1, 0]
504+
time_trunc = self.accel[:n2 - n1, 0]
502505
accel_trunc = self.accel[n1:n2, 1]
503506
truncated = np.column_stack((time_trunc, accel_trunc))
504507

505508
if show_fig:
506509
ax = [None] * 3
507-
fig = plt.figure(figsize=(5,6))
510+
fig = plt.figure(figsize=(5, 6))
508511
fig.subplots_adjust(left=0.2)
509512

510-
ax[0] = fig.add_subplot(3,1,1)
511-
ax[0].plot(self.time, self.accel[:,1], 'gray', lw=1.75, label='original')
512-
ax[0].plot(self.time[n1:n2], truncated[:,1], 'm', lw=1., label='truncated')
513+
ax[0] = fig.add_subplot(3, 1, 1)
514+
ax[0].plot(self.time, self.accel[:, 1], 'gray', lw=1.75, label='original')
515+
ax[0].plot(self.time[n1:n2], truncated[:, 1], 'm', lw=1., label='truncated')
513516
ax[0].grid(ls=':')
514517
ax[0].set_ylabel('Accel. [m/s/s]')
515518
ax[0].legend(loc='best')
516519

517-
ax[1] = fig.add_subplot(3,1,2)
518-
ax[1].plot(self.time, self.veloc[:,1], 'gray', lw=1.75)
519-
ax[1].plot(self.time[n1:n2], sr.num_int(truncated)[0][:,1], 'm', lw=1.)
520+
ax[1] = fig.add_subplot(3, 1, 2)
521+
ax[1].plot(self.time, self.veloc[:, 1], 'gray', lw=1.75)
522+
ax[1].plot(self.time[n1:n2], sr.num_int(truncated)[0][:, 1], 'm', lw=1.)
520523
ax[1].grid(ls=':')
521524
ax[1].set_ylabel('Veloc. [m/s]')
522525

523-
ax[2] = fig.add_subplot(3,1,3)
524-
ax[2].plot(self.time, self.displ[:,1], 'gray', lw=1.75)
525-
ax[2].plot(self.time[n1:n2], sr.num_int(truncated)[1][:,1], 'm', lw=1.)
526+
ax[2] = fig.add_subplot(3, 1, 3)
527+
ax[2].plot(self.time, self.displ[:, 1], 'gray', lw=1.75)
528+
ax[2].plot(self.time[n1:n2], sr.num_int(truncated)[1][:, 1], 'm', lw=1.)
526529
ax[2].grid(ls=':')
527530
ax[2].set_ylabel('Displ. [m]')
528531
ax[2].set_xlabel('Time [sec]')
@@ -882,8 +885,8 @@ def save_accel(
882885
if unit == 'm/s/s':
883886
pass
884887
elif unit == 'g':
885-
data[:,1] = data[:,1] / 9.81
888+
data[:, 1] = data[:, 1] / 9.81
886889
elif unit in ['gal', 'cm/s/s']:
887-
data[:,1] = data[:,1] * 100.0
890+
data[:, 1] = data[:, 1] * 100.0
888891

889892
np.savetxt(fname, data, fmt=fmt, delimiter=sep)

PySeismoSoil/class_hh_calibration.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from . import helper_generic as hlp
66
from . import helper_hh_calibration as hhc
77

8+
89
class HH_Calibration:
910
"""
1011
Class implementation of the "HH calibration procedure" (HHC procedure). The
@@ -68,7 +69,8 @@ def __init__(self, vs_profile, *, GGmax_curves=None, Tmax_profile=None):
6869
self.GGmax_curves = GGmax_curves
6970
self.Tmax_profile = Tmax_profile
7071

71-
def fit(self, show_fig=False, save_fig=False, fig_output_dir=None,
72+
def fit(
73+
self, show_fig=False, save_fig=False, fig_output_dir=None,
7274
save_HH_G_file=False, HH_G_file_dir=None, profile_name=None,
7375
verbose=True,
7476
):

PySeismoSoil/class_parameters.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ def get_damping(self, strain_in_pct=np.logspace(-2, 1)):
142142
print('You did not provide a function to calculate shear stress.')
143143
return None
144144
damping_in_1 = sr.calc_damping_from_param(
145-
self.data, strain_in_pct/100., self.func_stress,
145+
self.data, strain_in_pct / 100., self.func_stress,
146146
)
147147
return damping_in_1 * 100
148148

PySeismoSoil/class_simulation.py

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ class Linear_Simulation(Simulation):
107107
----------
108108
Attributes same as the inputs
109109
"""
110-
def run(self, every_layer=True, deconv=False, show_fig=False,
110+
def run(
111+
self, every_layer=True, deconv=False, show_fig=False,
111112
save_fig=False, motion_name=None, save_txt=False,
112113
save_full_time_history=False, output_dir=None, verbose=True,
113114
):
@@ -168,7 +169,7 @@ def run(self, every_layer=True, deconv=False, show_fig=False,
168169
Vs_Profile(new_profile, density_unit='g/cm^3'),
169170
max_a_v_d=max_avd,
170171
max_strain_stress=max_gt,
171-
trans_func=Frequency_Spectrum(tf, df=freq_array[1]-freq_array[0]),
172+
trans_func=Frequency_Spectrum(tf, df=freq_array[1] - freq_array[0]),
172173
time_history_accel=out_a,
173174
time_history_veloc=out_v,
174175
time_history_displ=out_d,
@@ -239,7 +240,8 @@ def __init__(
239240
soil_profile, GGmax_and_damping_curves=GGmax_and_damping_curves,
240241
)
241242

242-
def run(self, verbose=True, show_fig=False, save_fig=False,
243+
def run(
244+
self, verbose=True, show_fig=False, save_fig=False,
243245
motion_name=None, save_txt=False, save_full_time_history=False,
244246
output_dir=None,
245247
):
@@ -293,7 +295,7 @@ def run(self, verbose=True, show_fig=False, save_fig=False,
293295
Vs_Profile(new_profile, density_unit='g/cm^3'),
294296
max_a_v_d=max_avd,
295297
max_strain_stress=max_gt,
296-
trans_func=Frequency_Spectrum(tf, df=freq_array[1]-freq_array[0]),
298+
trans_func=Frequency_Spectrum(tf, df=freq_array[1] - freq_array[0]),
297299
time_history_accel=out_a,
298300
time_history_veloc=out_v,
299301
time_history_displ=out_d,
@@ -351,7 +353,8 @@ def __init__(
351353
)
352354
sim.check_layer_count(soil_profile, G_param=G_param, xi_param=xi_param)
353355

354-
def run(self, sim_dir=None, motion_name=None, save_txt=False,
356+
def run(
357+
self, sim_dir=None, motion_name=None, save_txt=False,
355358
save_full_time_history=True, show_fig=False, save_fig=False,
356359
remove_sim_dir=False, verbose=True,
357360
):
@@ -434,7 +437,7 @@ def run(self, sim_dir=None, motion_name=None, save_txt=False,
434437
[1.32629E+01, -1.33696E-01, 2.14647E-01],
435438
])
436439

437-
#--------- Re-discretize Vs profile -----------------------------------
440+
# --------- Re-discretize Vs profile -----------------------------------
438441
new_profile = sr.stratify(self.soil_profile.vs_profile)
439442
new_profile[:, 3] /= 1000.0 # convert to g/cm3 to pass to NLHH
440443

@@ -448,12 +451,12 @@ def run(self, sim_dir=None, motion_name=None, save_txt=False,
448451
t = input_accel[:, 0]
449452
nt_out = len(t)
450453

451-
#--------- Create a dummy "curves" for Fortran ------------------------
454+
# --------- Create a dummy "curves" for Fortran ------------------------
452455
mgc, mdc = self.G_param.construct_curves(strain_in_pct=strain_in_pct)
453456
mgdc = Multiple_GGmax_Damping_Curves(mgc_and_mdc=(mgc, mdc))
454457
curves = mgdc.get_curve_matrix()
455458

456-
#--------- Prepare tabk.dat file --------------------------------------
459+
# --------- Prepare tabk.dat file --------------------------------------
457460
if hlp.detect_OS() == 'Windows':
458461
exec_ext = 'exe'
459462
elif hlp.detect_OS() == 'Darwin':
@@ -468,21 +471,21 @@ def run(self, sim_dir=None, motion_name=None, save_txt=False,
468471
shutil.copy(os.path.join(dir_exec_files, 'NLHH.%s' % exec_ext), sim_dir)
469472
np.savetxt(os.path.join(sim_dir, 'tabk.dat'), tabk, delimiter='\t')
470473

471-
#-------- Prepare control.dat file ------------------------------------
474+
# -------- Prepare control.dat file ------------------------------------
472475
with open(os.path.join(sim_dir, 'control.dat'), 'w') as fp:
473476
fp.write(
474477
'%6.1f %6.0f %6.0f %6.0f %6.0f %10.0f %6.0f %6.0f %6.0f' \
475478
% (f_max, ppw, n_dt, n_bound, n_layer, nt_out, n_ma, N_spr, N_obs)
476479
)
477480

478-
#-------- Write data to files for the Fortran kernel to read ----------
481+
# -------- Write data to files for the Fortran kernel to read ----------
479482
np.savetxt(os.path.join(sim_dir, 'profile.dat'), new_profile)
480483
np.savetxt(os.path.join(sim_dir, 'incident.dat'), input_accel)
481484
np.savetxt(os.path.join(sim_dir, 'curve.dat'), curves)
482485
np.savetxt(os.path.join(sim_dir, 'HH_G.dat'), self.G_param.serialize_to_2D_array())
483486
np.savetxt(os.path.join(sim_dir, 'HH_x.dat'), self.xi_param.serialize_to_2D_array())
484487

485-
#------- Execute Fortran kernel ---------------------------------------
488+
# ------- Execute Fortran kernel ---------------------------------------
486489
cwd = os.getcwd()
487490
os.chdir(sim_dir)
488491
if hlp.detect_OS() == 'Windows':
@@ -507,7 +510,7 @@ def run(self, sim_dir=None, motion_name=None, save_txt=False,
507510
if verbose:
508511
print('Simulation finished. Now post processing.')
509512

510-
#------------ Post-process files --------------------------------------
513+
# ------------ Post-process files --------------------------------------
511514
layer_boundary_depth = np.genfromtxt('node_depth.dat').T
512515
layer_midpoint_depth = np.genfromtxt('layer_depth.dat').T
513516
out_a = np.genfromtxt('out_a.dat')
@@ -549,7 +552,7 @@ def run(self, sim_dir=None, motion_name=None, save_txt=False,
549552
)
550553
os.chdir(cwd)
551554

552-
#------------ Create sim_results object and plot and/or save ----------
555+
# ------------ Create sim_results object and plot and/or save ----------
553556
sim_results = Simulation_Results(
554557
self.input_motion,
555558
Ground_Motion(accel_surface_2col, unit='m'),

0 commit comments

Comments
 (0)