pyStrata 0.5.0__tar.gz → 0.5.2__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.
Files changed (31) hide show
  1. {pyStrata-0.5.0 → pystrata-0.5.2}/HISTORY.rst +12 -0
  2. {pyStrata-0.5.0 → pystrata-0.5.2}/PKG-INFO +40 -29
  3. {pyStrata-0.5.0 → pystrata-0.5.2}/README.rst +23 -11
  4. {pyStrata-0.5.0 → pystrata-0.5.2}/pystrata/__init__.py +2 -4
  5. {pyStrata-0.5.0 → pystrata-0.5.2}/pystrata/motion.py +1 -1
  6. {pyStrata-0.5.0 → pystrata-0.5.2}/pystrata/output.py +7 -4
  7. {pyStrata-0.5.0 → pystrata-0.5.2}/pystrata/propagation.py +1 -1
  8. {pyStrata-0.5.0 → pystrata-0.5.2}/pystrata/site.py +117 -36
  9. {pyStrata-0.5.0 → pystrata-0.5.2}/pystrata/variation.py +53 -25
  10. {pyStrata-0.5.0/pyStrata.egg-info → pystrata-0.5.2/pystrata.egg-info}/PKG-INFO +40 -29
  11. pystrata-0.5.2/pystrata.egg-info/SOURCES.txt +26 -0
  12. {pyStrata-0.5.0 → pystrata-0.5.2}/requirements.txt +3 -1
  13. pystrata-0.5.2/setup.cfg +37 -0
  14. pystrata-0.5.2/setup.py +6 -0
  15. {pyStrata-0.5.0 → pystrata-0.5.2}/tests/__init__.py +0 -0
  16. pyStrata-0.5.0/tests/test_motion.py → pystrata-0.5.2/tests/motion_test.py +1 -1
  17. pyStrata-0.5.0/tests/test_notebooks.py → pystrata-0.5.2/tests/notebooks_test.py +1 -1
  18. pyStrata-0.5.0/tests/test_output.py → pystrata-0.5.2/tests/output_test.py +0 -3
  19. pyStrata-0.5.0/tests/test_propagation.py → pystrata-0.5.2/tests/propagation_test.py +12 -4
  20. pyStrata-0.5.0/tests/test_site.py → pystrata-0.5.2/tests/site_test.py +20 -0
  21. pyStrata-0.5.0/tests/test_variation.py → pystrata-0.5.2/tests/variation_test.py +43 -5
  22. pyStrata-0.5.0/pyStrata.egg-info/SOURCES.txt +0 -27
  23. pyStrata-0.5.0/pyStrata.egg-info/requires.txt +0 -10
  24. pyStrata-0.5.0/setup.cfg +0 -26
  25. pyStrata-0.5.0/setup.py +0 -48
  26. {pyStrata-0.5.0 → pystrata-0.5.2}/AUTHORS.rst +0 -0
  27. {pyStrata-0.5.0 → pystrata-0.5.2}/LICENSE +0 -0
  28. {pyStrata-0.5.0 → pystrata-0.5.2}/MANIFEST.in +0 -0
  29. {pyStrata-0.5.0 → pystrata-0.5.2}/pystrata/tools.py +0 -0
  30. {pyStrata-0.5.0/pyStrata.egg-info → pystrata-0.5.2/pystrata.egg-info}/dependency_links.txt +0 -0
  31. {pyStrata-0.5.0/pyStrata.egg-info → pystrata-0.5.2/pystrata.egg-info}/top_level.txt +0 -0
@@ -1,6 +1,18 @@
1
1
  History
2
2
  =======
3
3
 
4
+ v0.5.2 (2023-01-18)
5
+ -------------------
6
+ - Fixed: Providing unsmoothed transfer function output
7
+ - Fixed: MenqSoilType
8
+
9
+ v0.5.1 (2022-09-22)
10
+ -------------------
11
+ - Fixed: Correlation model from Toro. Previously used rho_0 instead of d_0, and the
12
+ wrong depth
13
+ - Renamed: BedrockDepthVariation to HalfSpaceDepthVariation
14
+ - Fixed: HalfSpaceDepthVariation was removing the last layer
15
+
4
16
  v0.5.0 (2022-06-14)
5
17
  -------------------
6
18
  - Renamed to `pyStrata`.
@@ -1,23 +1,11 @@
1
1
  Metadata-Version: 2.1
2
- Name: pyStrata
3
- Version: 0.5.0
4
- Summary: Site Response Analysis with Python
5
- Home-page: http://github.com/arkottke/pystrata
6
- Author: Albert Kottke
2
+ Name: pystrata
3
+ Version: 0.5.2
4
+ Summary: Site response analysis with Python
5
+ Home-page: https://github.com/arkottke/pystrata
6
+ Author: Albert R. Kottke
7
7
  Author-email: albert.kottke@gmail.com
8
8
  License: MIT
9
- Keywords: site response
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Environment :: Console
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Natural Language :: English
14
- Classifier: Operating System :: OS Independent
15
- Classifier: Programming Language :: Python
16
- Classifier: Programming Language :: Python :: 3.6
17
- Classifier: Topic :: Scientific/Engineering
18
- Classifier: Intended Audience :: Science/Research
19
- Description-Content-Type: text/x-rst
20
- Provides-Extra: dataframe
21
9
  License-File: LICENSE
22
10
  License-File: AUTHORS.rst
23
11
 
@@ -40,9 +28,20 @@ Strata_. These features include:
40
28
  - equivalent-linear with frequency dependent properties
41
29
  - quarter wavelength
42
30
  - Nonlinear curve models:
43
- - Darendeli (2001)
44
- - Menq (2004)
45
- - Kishida (2012)
31
+ - Predictive models:
32
+ - Darendeli (2001)
33
+ - Menq (2004)
34
+ - Kishida (2012)
35
+ - Curves:
36
+ - Vucetic & Dobry (1991)
37
+ - EPRI (1993)
38
+ - GEI (1983)
39
+ - GeoMatrix (1990)
40
+ - Idriss (1990)
41
+ - Imperial Valley Soils
42
+ - Iwasaki
43
+ - Peninsular Range
44
+ - Seed & Idriss
46
45
  - Site and soil property uncertainty:
47
46
  - Toro (1994) Vs correlation model
48
47
  - G/Gmax and D uncertainty:
@@ -78,28 +77,40 @@ directory`_. An interactive Jupyter interface of these examples is available on
78
77
 
79
78
  .. _Strata: https://github.com/arkottke/strata
80
79
  .. _DOI: https://zenodo.org/badge/latestdoi/8959678
81
- .. _`examples directory`: https://github.com/arkottke/pystrata/tree/master/examples
80
+ .. _`examples directory`: https://github.com/arkottke/pystrata/tree/main/examples
82
81
 
83
82
  .. |PyPi Cheese Shop| image:: https://img.shields.io/pypi/v/pystrata.svg
84
83
  :target: https://pypi.python.org/pypi/pystrata
85
- .. |Build Status| image:: https://img.shields.io/travis/arkottke/pystrata.svg
86
- :target: https://travis-ci.org/arkottke/pystrata
84
+ .. |Build Status| image:: https://img.shields.io/github/workflow/status/arkottke/pystrata/Python%20application
85
+ :alt: GitHub Workflow Status
86
+ :target: https://github.com/arkottke/pystrata/actions/workflows/python-app.yml
87
87
  .. |Documentation Status| image:: https://readthedocs.org/projects/pystrata/badge/?version=latest&style=flat
88
88
  :target: https://pystrata.readthedocs.org
89
- .. |Code Quality| image:: https://api.codacy.com/project/badge/Grade/6dbbb3a4279744d697b9bfe08af19ded
90
- :target: https://www.codacy.com/app/arkottke/pystrata
91
- .. |Test Coverage| image:: https://api.codacy.com/project/badge/Coverage/6dbbb3a4279744d697b9bfe08af19ded
92
- :target: https://www.codacy.com/app/arkottke/pystrata
89
+ .. |Code Quality| image:: https://app.codacy.com/project/badge/Grade/6dbbb3a4279744d697b9bfe08af19ded
90
+ :target: https://www.codacy.com/gh/arkottke/pystrata/dashboard
91
+ .. |Test Coverage| image:: https://app.codacy.com/project/badge/Coverage/6dbbb3a4279744d697b9bfe08af19ded
92
+ :target: https://www.codacy.com/gh/arkottke/pystrata/dashboard
93
93
  .. |License| image:: https://img.shields.io/badge/license-MIT-blue.svg
94
94
  .. |Zenodo| image:: https://zenodo.org/badge/8959678.svg
95
95
  :target: https://zenodo.org/badge/latestdoi/8959678
96
96
  .. |MyBinder| image:: https://mybinder.org/badge_logo.svg
97
- :target: https://mybinder.org/v2/gh/arkottke/pystrata/master?filepath=examples
98
-
97
+ :target: https://mybinder.org/v2/gh/arkottke/pystrata/main?filepath=examples
99
98
 
100
99
  History
101
100
  =======
102
101
 
102
+ v0.5.2 (2023-01-18)
103
+ -------------------
104
+ - Fixed: Providing unsmoothed transfer function output
105
+ - Fixed: MenqSoilType
106
+
107
+ v0.5.1 (2022-09-22)
108
+ -------------------
109
+ - Fixed: Correlation model from Toro. Previously used rho_0 instead of d_0, and the
110
+ wrong depth
111
+ - Renamed: BedrockDepthVariation to HalfSpaceDepthVariation
112
+ - Fixed: HalfSpaceDepthVariation was removing the last layer
113
+
103
114
  v0.5.0 (2022-06-14)
104
115
  -------------------
105
116
  - Renamed to `pyStrata`.
@@ -17,9 +17,20 @@ Strata_. These features include:
17
17
  - equivalent-linear with frequency dependent properties
18
18
  - quarter wavelength
19
19
  - Nonlinear curve models:
20
- - Darendeli (2001)
21
- - Menq (2004)
22
- - Kishida (2012)
20
+ - Predictive models:
21
+ - Darendeli (2001)
22
+ - Menq (2004)
23
+ - Kishida (2012)
24
+ - Curves:
25
+ - Vucetic & Dobry (1991)
26
+ - EPRI (1993)
27
+ - GEI (1983)
28
+ - GeoMatrix (1990)
29
+ - Idriss (1990)
30
+ - Imperial Valley Soils
31
+ - Iwasaki
32
+ - Peninsular Range
33
+ - Seed & Idriss
23
34
  - Site and soil property uncertainty:
24
35
  - Toro (1994) Vs correlation model
25
36
  - G/Gmax and D uncertainty:
@@ -55,20 +66,21 @@ directory`_. An interactive Jupyter interface of these examples is available on
55
66
 
56
67
  .. _Strata: https://github.com/arkottke/strata
57
68
  .. _DOI: https://zenodo.org/badge/latestdoi/8959678
58
- .. _`examples directory`: https://github.com/arkottke/pystrata/tree/master/examples
69
+ .. _`examples directory`: https://github.com/arkottke/pystrata/tree/main/examples
59
70
 
60
71
  .. |PyPi Cheese Shop| image:: https://img.shields.io/pypi/v/pystrata.svg
61
72
  :target: https://pypi.python.org/pypi/pystrata
62
- .. |Build Status| image:: https://img.shields.io/travis/arkottke/pystrata.svg
63
- :target: https://travis-ci.org/arkottke/pystrata
73
+ .. |Build Status| image:: https://img.shields.io/github/workflow/status/arkottke/pystrata/Python%20application
74
+ :alt: GitHub Workflow Status
75
+ :target: https://github.com/arkottke/pystrata/actions/workflows/python-app.yml
64
76
  .. |Documentation Status| image:: https://readthedocs.org/projects/pystrata/badge/?version=latest&style=flat
65
77
  :target: https://pystrata.readthedocs.org
66
- .. |Code Quality| image:: https://api.codacy.com/project/badge/Grade/6dbbb3a4279744d697b9bfe08af19ded
67
- :target: https://www.codacy.com/app/arkottke/pystrata
68
- .. |Test Coverage| image:: https://api.codacy.com/project/badge/Coverage/6dbbb3a4279744d697b9bfe08af19ded
69
- :target: https://www.codacy.com/app/arkottke/pystrata
78
+ .. |Code Quality| image:: https://app.codacy.com/project/badge/Grade/6dbbb3a4279744d697b9bfe08af19ded
79
+ :target: https://www.codacy.com/gh/arkottke/pystrata/dashboard
80
+ .. |Test Coverage| image:: https://app.codacy.com/project/badge/Coverage/6dbbb3a4279744d697b9bfe08af19ded
81
+ :target: https://www.codacy.com/gh/arkottke/pystrata/dashboard
70
82
  .. |License| image:: https://img.shields.io/badge/license-MIT-blue.svg
71
83
  .. |Zenodo| image:: https://zenodo.org/badge/8959678.svg
72
84
  :target: https://zenodo.org/badge/latestdoi/8959678
73
85
  .. |MyBinder| image:: https://mybinder.org/badge_logo.svg
74
- :target: https://mybinder.org/v2/gh/arkottke/pystrata/master?filepath=examples
86
+ :target: https://mybinder.org/v2/gh/arkottke/pystrata/main?filepath=examples
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  # The MIT License (MIT)
2
3
  #
3
4
  # Copyright (c) 2016-2022 Albert Kottke
@@ -19,9 +20,6 @@
19
20
  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
21
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
22
  # SOFTWARE.
22
-
23
- from pkg_resources import get_distribution
24
-
25
23
  from . import motion
26
24
  from . import output
27
25
  from . import propagation
@@ -35,4 +33,4 @@ __author__ = "Albert Kottke"
35
33
  __copyright__ = "Copyright 2016-2022 Albert Kottke"
36
34
  __license__ = "MIT"
37
35
  __title__ = "pyStrata"
38
- __version__ = get_distribution("pyStrata").version
36
+ __version__ = "0.5.2"
@@ -200,7 +200,7 @@ class TimeSeriesMotion(Motion):
200
200
  tf : :class:`numpy.ndarray`
201
201
  Complex-valued transfer function with length equal to `self.freq`.
202
202
  """
203
- return -(osc_freq ** 2.0) / (
203
+ return -(osc_freq**2.0) / (
204
204
  np.square(self.freqs)
205
205
  - np.square(osc_freq)
206
206
  - 2.0j * damping * osc_freq * self.freqs
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  # The MIT License (MIT)
2
3
  #
3
4
  # Copyright (c) 2016-2021 Albert Kottke
@@ -406,7 +407,7 @@ class AriasIntensityTSOutput(AccelerationTSOutput):
406
407
 
407
408
  def _modify_values(self, calc, location, values):
408
409
  time_step = calc.motion.time_step
409
- values = scipy.integrate.cumtrapz(values ** 2, dx=time_step)
410
+ values = scipy.integrate.cumtrapz(values**2, dx=time_step)
410
411
  values *= GRAVITY * np.pi / 2
411
412
  return values
412
413
 
@@ -486,15 +487,17 @@ class FourierAmplitudeSpectrumOutput(LocationBasedOutput):
486
487
  loc = self._get_location(calc)
487
488
  tf = calc.calc_accel_tf(calc.loc_input, loc)
488
489
 
489
- if self.ko_bandwidth:
490
- smoothed = pykooh.smooth(
490
+ if self._ko_bandwidth is None:
491
+ tf = np.interp(self.freqs, calc.motion.freqs, tf)
492
+ else:
493
+ tf = pykooh.smooth(
491
494
  self.freqs,
492
495
  calc.motion.freqs,
493
496
  np.abs(tf * calc.motion.fourier_amps),
494
497
  self.ko_bandwidth,
495
498
  )
496
499
 
497
- self._add_values(smoothed)
500
+ self._add_values(tf)
498
501
 
499
502
 
500
503
  class ResponseSpectrumOutput(LocationBasedOutput):
@@ -452,7 +452,7 @@ class LinearElasticCalculator(AbstractCalculator):
452
452
  - self._waves_b[lout.index, :] * np.exp(-cterm)
453
453
  )
454
454
  )
455
- denom = -(ang_freqs ** 2) * self.wave_at_location(lin)
455
+ denom = -(ang_freqs**2) * self.wave_at_location(lin)
456
456
 
457
457
  # Only compute transfer function for non-zero frequencies
458
458
  mask = ~np.isclose(ang_freqs, 0)
@@ -1,3 +1,4 @@
1
+ # -*- coding: utf-8 -*-
1
2
  # The MIT License (MIT)
2
3
  #
3
4
  # Copyright (c) 2016-2018 Albert Kottke
@@ -22,7 +23,10 @@
22
23
  from __future__ import annotations
23
24
 
24
25
  import collections
26
+ import warnings
25
27
  from dataclasses import dataclass
28
+ from pathlib import Path
29
+ from typing import List
26
30
  from typing import Optional
27
31
  from typing import Tuple
28
32
 
@@ -30,6 +34,7 @@ import matplotlib.pyplot as plt
30
34
  import numpy as np
31
35
  import numpy.typing as npt
32
36
  import scipy.constants
37
+ import tomli
33
38
  from scipy.interpolate import interp1d
34
39
 
35
40
  from .motion import GRAVITY
@@ -39,6 +44,32 @@ COMP_MODULUS_MODEL = "dormieux"
39
44
 
40
45
  KPA_TO_ATM = scipy.constants.kilo / scipy.constants.atm
41
46
 
47
+ PUBLISHED_CURVES = None
48
+
49
+
50
+ def _load_published_curves():
51
+ """Load published nonlinear curves."""
52
+ global PUBLISHED_CURVES
53
+
54
+ fpath = Path(__file__).parent / "data" / "published_curves.toml"
55
+ with fpath.open("rb") as fp:
56
+ models = tomli.load(fp)["models"]
57
+
58
+ # Count to make sure there aren't repeated names
59
+ counts = collections.Counter([m["name"] for m in models])
60
+ if max(counts.values()) > 1:
61
+ names = ", ".join([k for k, v in counts.items() if v > 1])
62
+ warnings.warn(f"Repeated names in {fpath}: " + names)
63
+
64
+ PUBLISHED_CURVES = {m["name"]: m for m in models}
65
+
66
+
67
+ def known_published_curves() -> List[dict]:
68
+ """List of published curves in the database."""
69
+ if not PUBLISHED_CURVES:
70
+ _load_published_curves()
71
+ return list(PUBLISHED_CURVES.keys())
72
+
42
73
 
43
74
  class NonlinearProperty(object):
44
75
  """Class for nonlinear property with a method for log-linear interpolation.
@@ -76,6 +107,18 @@ class NonlinearProperty(object):
76
107
 
77
108
  self._update()
78
109
 
110
+ @classmethod
111
+ def from_published(cls, name, param):
112
+ assert param in cls.PARAMS
113
+ if not PUBLISHED_CURVES:
114
+ _load_published_curves()
115
+
116
+ selected = PUBLISHED_CURVES[name][param]
117
+
118
+ return cls(
119
+ name, strains=selected["strains"], values=selected["values"], param=param
120
+ )
121
+
79
122
  def __call__(self, strains):
80
123
  """Return the nonlinear property at a specific strain.
81
124
 
@@ -192,6 +235,21 @@ class SoilType(object):
192
235
  self.mod_reduc = mod_reduc
193
236
  self.damping = damping
194
237
 
238
+ @classmethod
239
+ def from_published(cls, name, unit_wt, *args):
240
+ if not PUBLISHED_CURVES:
241
+ _load_published_curves()
242
+
243
+ model_mr = args[0]
244
+ model_d = args[1] if len(args) > 1 else args[0]
245
+
246
+ return cls(
247
+ name,
248
+ unit_wt=unit_wt,
249
+ mod_reduc=NonlinearProperty.from_published(model_mr, "mod_reduc"),
250
+ damping=NonlinearProperty.from_published(model_d, "damping"),
251
+ )
252
+
195
253
  def copy(self):
196
254
  return SoilType(self.name, self.unit_wt, self.mod_reduc, self.damping)
197
255
 
@@ -227,7 +285,7 @@ class SoilType(object):
227
285
  # return all(
228
286
  # getattr(self, attr) == getattr(other, attr)
229
287
  # for attr in ['name', 'unit_wt', 'mod_reduc', 'damping'])
230
- return self.__dict__ == other.__dict__
288
+ return (type(self) == type(other)) and (self.__dict__ == other.__dict__)
231
289
 
232
290
  def __hash__(self):
233
291
  return hash(self.__dict__.values())
@@ -269,22 +327,22 @@ class ModifiedHyperbolicSoilType(SoilType):
269
327
  - strain_ref_percent
270
328
  * np.log((strains_percent + strain_ref_percent) / strain_ref_percent)
271
329
  )
272
- / (strains_percent ** 2 / (strains_percent + strain_ref_percent))
330
+ / (strains_percent**2 / (strains_percent + strain_ref_percent))
273
331
  - 2.0
274
332
  )
275
333
  # Correction between perfect hyperbolic strain model and modified
276
334
  # model [%].
277
- c1 = -1.1143 * self.curvature ** 2 + 1.8618 * self.curvature + 0.2523
278
- c2 = 0.0805 * self.curvature ** 2 - 0.0710 * self.curvature - 0.0095
279
- c3 = -0.0005 * self.curvature ** 2 + 0.0002 * self.curvature + 0.0003
335
+ c1 = -1.1143 * self.curvature**2 + 1.8618 * self.curvature + 0.2523
336
+ c2 = 0.0805 * self.curvature**2 - 0.0710 * self.curvature - 0.0095
337
+ c3 = -0.0005 * self.curvature**2 + 0.0002 * self.curvature + 0.0003
280
338
  damping_masing = (
281
339
  c1 * damping_masing_a1
282
- + c2 * damping_masing_a1 ** 2
283
- + c3 * damping_masing_a1 ** 3
340
+ + c2 * damping_masing_a1**2
341
+ + c3 * damping_masing_a1**3
284
342
  )
285
343
 
286
344
  # Compute the damping correction in percent
287
- d_correction = self.masing_scaling * damping_masing * mod_reduc ** 0.1
345
+ d_correction = self.masing_scaling * damping_masing * mod_reduc**0.1
288
346
 
289
347
  # Prevent the damping from reducing as it can at large strains
290
348
  damping = np.maximum.accumulate(d_correction / 100.0)
@@ -371,14 +429,14 @@ class TwoParamModifiedHyperbolicSoilType(SoilType):
371
429
  stress_mean_atm = stress_mean * KPA_TO_ATM
372
430
 
373
431
  # Convert from percent to decimal strain
374
- strain_mr = C.g1 * stress_mean_atm ** C.g2 / 100
432
+ strain_mr = C.g1 * stress_mean_atm**C.g2 / 100
375
433
  b = C.b1 + C.b2 * stress_mean_atm
376
434
  values_mr = 1 / ((1 + (strains / strain_mr) ** C.a)) ** b
377
435
  mod_reduc = NonlinearProperty(name, strains, values_mr)
378
436
 
379
- d_min = C.d0 * stress_mean_atm ** C.d1
437
+ d_min = C.d0 * stress_mean_atm**C.d1
380
438
  # Convert from percent to decimal strain
381
- strain_dr = (C.gd1 * stress_mean_atm ** C.gd2) / 100
439
+ strain_dr = (C.gd1 * stress_mean_atm**C.gd2) / 100
382
440
  term = (strains / strain_dr) ** C.c
383
441
  # Convert to damping in decimal
384
442
  values_d = (C.d * term + d_min) / (term + 1) / 100
@@ -437,7 +495,7 @@ class DarendeliSoilType(ModifiedHyperbolicSoilType):
437
495
  def _calc_damping_min(self):
438
496
  """minimum damping [decimal]"""
439
497
  return (
440
- (0.8005 + 0.0129 * self._plas_index * self._ocr ** -0.1069)
498
+ (0.8005 + 0.0129 * self._plas_index * self._ocr**-0.1069)
441
499
  * (self._stress_mean * KPA_TO_ATM) ** -0.2889
442
500
  * (1 + 0.2919 * np.log(self._freq))
443
501
  ) / 100
@@ -451,7 +509,7 @@ class DarendeliSoilType(ModifiedHyperbolicSoilType):
451
509
  def strain_ref(self):
452
510
  """reference strain [decimal]"""
453
511
  return (
454
- (0.0352 + 0.0010 * self._plas_index * self._ocr ** 0.3246)
512
+ (0.0352 + 0.0010 * self._plas_index * self._ocr**0.3246)
455
513
  * (self._stress_mean * KPA_TO_ATM) ** 0.3483
456
514
  ) / 100
457
515
 
@@ -464,7 +522,7 @@ class DarendeliSoilType(ModifiedHyperbolicSoilType):
464
522
  return fmt.format(self._plas_index, self._ocr, self._stress_mean)
465
523
 
466
524
 
467
- class MenqSoilType(DarendeliSoilType):
525
+ class MenqSoilType(ModifiedHyperbolicSoilType):
468
526
  """
469
527
  Menq SoilType for gravelly soils.
470
528
 
@@ -510,18 +568,23 @@ class MenqSoilType(DarendeliSoilType):
510
568
  def _calc_damping_min(self):
511
569
  return (
512
570
  0.55
513
- * self._uniformity_coeff ** 0.1
514
- * self._diam_mean ** -0.3
571
+ * self._uniformity_coeff**0.1
572
+ * self._diam_mean**-0.3
515
573
  * (self._stress_mean * KPA_TO_ATM) ** -0.08
516
574
  ) / 100
517
575
 
576
+ @property
577
+ def masing_scaling(self):
578
+ # Masing correction factor
579
+ return 0.6329 - 0.00566 * np.log(self._num_cycles)
580
+
518
581
  @property
519
582
  def strain_ref(self):
520
583
  return (
521
584
  0.12
522
- * self._uniformity_coeff ** -0.6
585
+ * self._uniformity_coeff**-0.6
523
586
  * (self._stress_mean * KPA_TO_ATM)
524
- ** (0.5 * self._uniformity_coeff ** -0.15)
587
+ ** (0.5 * self._uniformity_coeff**-0.15)
525
588
  ) / 100
526
589
 
527
590
  @property
@@ -758,13 +821,7 @@ class Layer(object):
758
821
 
759
822
  self._soil_type = soil_type
760
823
  self._thickness = thickness
761
- self._initial_shear_vel = shear_vel
762
-
763
- self._damping = None
764
- self._shear_mod = None
765
- self._strain = None
766
- self.strain_max = None
767
- self.reset()
824
+ self.initial_shear_vel = shear_vel
768
825
 
769
826
  self._depth = 0
770
827
  self._stress_vert = 0
@@ -781,6 +838,20 @@ class Layer(object):
781
838
  f"soil_type={st_name})>"
782
839
  )
783
840
 
841
+ def __eq__(self, other):
842
+ attrs = ["_soil_type", "_thickness", "initial_shear_vel"]
843
+ return (type(self) == type(other)) and all(
844
+ [getattr(self, a) == getattr(other, a) for a in attrs]
845
+ )
846
+
847
+ def __hash__(self):
848
+ return hash(self.__dict__.values())
849
+
850
+ @classmethod
851
+ def copy_of(cls, other):
852
+ """Return a copy of the Layer instance with previously defined SoilType."""
853
+ return cls(other.soil_type, other.thickness, other.shear_vel)
854
+
784
855
  @property
785
856
  def depth(self):
786
857
  """Depth to the top of the layer [m]."""
@@ -796,11 +867,6 @@ class Layer(object):
796
867
  """Depth to the base of the layer [m]."""
797
868
  return self._depth + self._thickness
798
869
 
799
- @classmethod
800
- def duplicate(cls, other):
801
- """Create a copy of the layer."""
802
- return cls(other.soil_type, other.thickness, other.shear_vel)
803
-
804
870
  @property
805
871
  def density(self):
806
872
  """Density of soil in [kg/m³]."""
@@ -818,13 +884,21 @@ class Layer(object):
818
884
  @property
819
885
  def initial_shear_mod(self):
820
886
  """Initial (small-strain) shear modulus [kN/m²]."""
821
- return self.density * self.initial_shear_vel ** 2
887
+ return self.density * self.initial_shear_vel**2
822
888
 
823
889
  @property
824
890
  def initial_shear_vel(self):
825
891
  """Initial (small-strain) shear-wave velocity [m/s]."""
826
892
  return self._initial_shear_vel
827
893
 
894
+ @initial_shear_vel.setter
895
+ def initial_shear_vel(self, value: float):
896
+ """Set initial (small-strain) shear-wave velocity [m/s]."""
897
+
898
+ self._initial_shear_vel = value
899
+ # Reset the iterated values
900
+ self.reset()
901
+
828
902
  @property
829
903
  def comp_shear_mod(self):
830
904
  """Strain-compatible complex shear modulus [kN/m²]."""
@@ -838,12 +912,12 @@ class Layer(object):
838
912
  # Simplifed shear modulus (Kramer, 1996)
839
913
  # Correct dissipated energy
840
914
  # Incorrect shear modulus: G * \sqrt{1 + 2 \beta^2 + \beta^4 }
841
- comp_factor = 1 - damping ** 2 + 2j * damping
915
+ comp_factor = 1 - damping**2 + 2j * damping
842
916
  elif COMP_MODULUS_MODEL == "dormieux":
843
917
  # Dormieux and Canou (1990)
844
918
  # Correct dissipated energy
845
919
  # Correct shear modulus:
846
- comp_factor = np.sqrt(1 - 4 * damping ** 2) + 2j * damping
920
+ comp_factor = np.sqrt(1 - 4 * damping**2) + 2j * damping
847
921
  else:
848
922
  raise NotImplementedError
849
923
  comp_shear_mod = self.shear_mod * comp_factor
@@ -864,6 +938,8 @@ class Layer(object):
864
938
  # Use a small initial value
865
939
  self._strain = IterativeValue(1e-6)
866
940
 
941
+ self.strain_max = None
942
+
867
943
  @property
868
944
  def shear_mod(self):
869
945
  """Strain-compatible shear modulus [kN//m²]."""
@@ -933,7 +1009,7 @@ class Layer(object):
933
1009
  @thickness.setter
934
1010
  def thickness(self, thickness):
935
1011
  self._thickness = thickness
936
- self._profile.update_layers(self, self._profile.index(self) + 1)
1012
+ self._profile.update_layers(self._profile.index(self) + 1)
937
1013
 
938
1014
  @property
939
1015
  def travel_time(self):
@@ -1050,6 +1126,11 @@ class Profile(collections.abc.Container):
1050
1126
  def __getitem__(self, key):
1051
1127
  return self.layers[key]
1052
1128
 
1129
+ @classmethod
1130
+ def copy_of(cls, other):
1131
+ """Return a copy of the profile with new Layer instances."""
1132
+ return cls([Layer.copy_of(layer) for layer in other], other.wt_depth)
1133
+
1053
1134
  def index(self, layer):
1054
1135
  return self.layers.index(layer)
1055
1136
 
@@ -1259,7 +1340,7 @@ class Profile(collections.abc.Container):
1259
1340
  depths_mid = self.depth_mid
1260
1341
  shear_vels = self.initial_shear_vel
1261
1342
 
1262
- mode_incr = depths_mid * thicks / shear_vels ** 2
1343
+ mode_incr = depths_mid * thicks / shear_vels**2
1263
1344
  # Mode shape is computed as the sumation from the base of
1264
1345
  # the profile. Need to append a 0 for the roll performed in the next
1265
1346
  # step
@@ -1269,7 +1350,7 @@ class Profile(collections.abc.Container):
1269
1350
  # can be calculated for two adjacent layers
1270
1351
  freq_fund = np.sqrt(
1271
1352
  4
1272
- * np.sum(thicks * depths_mid ** 2 / shear_vels ** 2)
1353
+ * np.sum(thicks * depths_mid**2 / shear_vels**2)
1273
1354
  / np.sum(
1274
1355
  thicks * np.sum(np.c_[shape, np.roll(shape, -1)], axis=1)[:-1] ** 2
1275
1356
  )
@@ -20,6 +20,7 @@
20
20
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
21
  # SOFTWARE.
22
22
  import copy
23
+ from abc import abstractmethod
23
24
  from typing import Dict
24
25
  from typing import List
25
26
  from typing import Optional
@@ -241,24 +242,47 @@ class ToroThicknessVariation(object):
241
242
  return varied
242
243
 
243
244
 
244
- class BedrockDepthVariation(object):
245
- def __init__(
246
- self,
247
- dist: stats.rv_continuous,
248
- discretize_kwds: Optional[Dict[str, float]] = None,
249
- ):
245
+ class HalfSpaceDepthVariation(object):
246
+ def __init__(self, dist: stats.rv_continuous):
250
247
  self._dist = dist
251
- self._discretize_kwds = discretize_kwds or dict(max_freq=50, wave_frac=2)
252
248
 
253
249
  def __call__(self, profile: site.Profile) -> site.Profile:
250
+ # Update the distribution with the central value of the profile
254
251
  varied_depth = self._dist.rvs()
255
252
 
253
+ # Find the layer
256
254
  index, depth_within = profile.lookup_depth(varied_depth)
257
255
 
258
- _profile = site.Profile([layer for layer in profile[: (index + 1)]])
259
- _profile[-1].thickness = depth_within
256
+ print(varied_depth, profile[-1].depth, index, depth_within)
257
+
258
+ half_space = profile[-1]
259
+
260
+ if index < (len(profile) - 1):
261
+ # Variation is within the layers
262
+ layers = [site.Layer.copy_of(layer) for layer in profile[: (index + 1)]]
263
+ # Reduce the thickness of the layer above the half-space
264
+ layers[-1]._thickness = depth_within
265
+ else:
266
+ # Variation extends past the depth of the model
267
+ orig_thick = profile[-2].thickness
268
+ total_thick = orig_thick + depth_within
269
+ count = np.ceil(total_thick // orig_thick).astype(int)
270
+
271
+ thick = total_thick / count
260
272
 
261
- return _profile.auto_discretize(**self._discretize_kwds)
273
+ print(count, thick)
274
+
275
+ # Don't copy half-space
276
+ layers = [site.Layer.copy_of(layer) for layer in profile[:-1]]
277
+ # Don't call the setter function as it needs a profile defined
278
+ layers[-1]._thickness = thick
279
+ parent = layers[-1]
280
+ for _ in range(count - 1):
281
+ layers.append(site.Layer.copy_of(parent))
282
+
283
+ layers.append(half_space)
284
+
285
+ return site.Profile(layers, profile.wt_depth)
262
286
 
263
287
 
264
288
  class LayerThicknessVariation(object):
@@ -302,17 +326,12 @@ class VelocityVariation(object):
302
326
  ln_vel = np.clip(ln_vel_rand, mean - offset, mean + offset)
303
327
  vel = np.exp(ln_vel)
304
328
 
305
- # Create the new layers
329
+ varied = site.Profile.copy_of(profile)
330
+ # Update the velocities
306
331
  end = None if self.vary_bedrock else -1
307
- # FIXME: Can we use .copy()?
308
- layers = [
309
- site.Layer(l.soil_type, l.thickness, vel[i])
310
- for i, l in enumerate(profile[:end])
311
- ]
312
- if not self.vary_bedrock:
313
- layers.append(profile[-1])
332
+ for i, v in enumerate(vel[:end]):
333
+ varied[i].initial_shear_vel = v
314
334
 
315
- varied = site.Profile(layers, profile.wt_depth)
316
335
  return varied
317
336
 
318
337
  def _calc_covar_matrix(self, profile):
@@ -341,6 +360,7 @@ class VelocityVariation(object):
341
360
 
342
361
  return mat
343
362
 
363
+ @abstractmethod
344
364
  def _calc_corr(self, profile):
345
365
  """Compute the adjacent-layer correlations.
346
366
 
@@ -356,6 +376,7 @@ class VelocityVariation(object):
356
376
  """
357
377
  raise NotImplementedError
358
378
 
379
+ @abstractmethod
359
380
  def _calc_ln_std(self, profile):
360
381
  """Compute the standard deviation for each layer.
361
382
 
@@ -497,13 +518,20 @@ class ToroVelocityVariation(VelocityVariation):
497
518
  corr : :class:`numpy.array`
498
519
  Adjacent-layer correlations
499
520
  """
500
- depth = profile.depth_mid[:-1]
521
+
522
+ # Toro defines the depth as the average midpoint depths of layers i and i-1.
523
+ depths_mid = np.array(profile.depth_mid)
524
+ depth = np.mean(np.c_[depths_mid[:-1], depths_mid[1:]], axis=1)
525
+
526
+ # t variable from Toro; defined as the difference of the midpoint depths
501
527
  thick = np.diff(depth)
502
- depth = depth[1:]
528
+ # Remove the depth associated with the final layer. We will set that it is
529
+ # perfectly correlated later.
530
+ depth = depth[:-1]
503
531
 
504
532
  # Depth dependent correlation
505
533
  corr_depth = self.rho_200 * np.power(
506
- (depth + self.rho_0) / (200 + self.rho_0), self.b
534
+ (depth + self.h_0) / (200 + self.h_0), self.b
507
535
  )
508
536
  corr_depth[depth > 200] = self.rho_200
509
537
 
@@ -627,7 +655,7 @@ class DepthDependToroVelVariation(ToroVelocityVariation):
627
655
  rho_200: float,
628
656
  h_0: float,
629
657
  b: float,
630
- ln_std_map=Optional[Dict[str,float]],
658
+ ln_std_map=Optional[Dict[str, float]],
631
659
  vary_bedrock=False,
632
660
  ):
633
661
  """Initialize the model."""
@@ -875,9 +903,9 @@ def iter_varied_profiles(
875
903
  var_velocity: VelocityVariation = None,
876
904
  var_soiltypes: SoilTypeVariation = None,
877
905
  ):
878
- for i in range(count):
906
+ for _ in range(count):
879
907
  # Copy the profile to form the realization
880
- p = profile
908
+ p = site.Profile.copy_of(profile)
881
909
 
882
910
  if var_thickness:
883
911
  p = var_thickness(p)
@@ -1,23 +1,11 @@
1
1
  Metadata-Version: 2.1
2
- Name: pyStrata
3
- Version: 0.5.0
4
- Summary: Site Response Analysis with Python
5
- Home-page: http://github.com/arkottke/pystrata
6
- Author: Albert Kottke
2
+ Name: pystrata
3
+ Version: 0.5.2
4
+ Summary: Site response analysis with Python
5
+ Home-page: https://github.com/arkottke/pystrata
6
+ Author: Albert R. Kottke
7
7
  Author-email: albert.kottke@gmail.com
8
8
  License: MIT
9
- Keywords: site response
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Environment :: Console
12
- Classifier: License :: OSI Approved :: MIT License
13
- Classifier: Natural Language :: English
14
- Classifier: Operating System :: OS Independent
15
- Classifier: Programming Language :: Python
16
- Classifier: Programming Language :: Python :: 3.6
17
- Classifier: Topic :: Scientific/Engineering
18
- Classifier: Intended Audience :: Science/Research
19
- Description-Content-Type: text/x-rst
20
- Provides-Extra: dataframe
21
9
  License-File: LICENSE
22
10
  License-File: AUTHORS.rst
23
11
 
@@ -40,9 +28,20 @@ Strata_. These features include:
40
28
  - equivalent-linear with frequency dependent properties
41
29
  - quarter wavelength
42
30
  - Nonlinear curve models:
43
- - Darendeli (2001)
44
- - Menq (2004)
45
- - Kishida (2012)
31
+ - Predictive models:
32
+ - Darendeli (2001)
33
+ - Menq (2004)
34
+ - Kishida (2012)
35
+ - Curves:
36
+ - Vucetic & Dobry (1991)
37
+ - EPRI (1993)
38
+ - GEI (1983)
39
+ - GeoMatrix (1990)
40
+ - Idriss (1990)
41
+ - Imperial Valley Soils
42
+ - Iwasaki
43
+ - Peninsular Range
44
+ - Seed & Idriss
46
45
  - Site and soil property uncertainty:
47
46
  - Toro (1994) Vs correlation model
48
47
  - G/Gmax and D uncertainty:
@@ -78,28 +77,40 @@ directory`_. An interactive Jupyter interface of these examples is available on
78
77
 
79
78
  .. _Strata: https://github.com/arkottke/strata
80
79
  .. _DOI: https://zenodo.org/badge/latestdoi/8959678
81
- .. _`examples directory`: https://github.com/arkottke/pystrata/tree/master/examples
80
+ .. _`examples directory`: https://github.com/arkottke/pystrata/tree/main/examples
82
81
 
83
82
  .. |PyPi Cheese Shop| image:: https://img.shields.io/pypi/v/pystrata.svg
84
83
  :target: https://pypi.python.org/pypi/pystrata
85
- .. |Build Status| image:: https://img.shields.io/travis/arkottke/pystrata.svg
86
- :target: https://travis-ci.org/arkottke/pystrata
84
+ .. |Build Status| image:: https://img.shields.io/github/workflow/status/arkottke/pystrata/Python%20application
85
+ :alt: GitHub Workflow Status
86
+ :target: https://github.com/arkottke/pystrata/actions/workflows/python-app.yml
87
87
  .. |Documentation Status| image:: https://readthedocs.org/projects/pystrata/badge/?version=latest&style=flat
88
88
  :target: https://pystrata.readthedocs.org
89
- .. |Code Quality| image:: https://api.codacy.com/project/badge/Grade/6dbbb3a4279744d697b9bfe08af19ded
90
- :target: https://www.codacy.com/app/arkottke/pystrata
91
- .. |Test Coverage| image:: https://api.codacy.com/project/badge/Coverage/6dbbb3a4279744d697b9bfe08af19ded
92
- :target: https://www.codacy.com/app/arkottke/pystrata
89
+ .. |Code Quality| image:: https://app.codacy.com/project/badge/Grade/6dbbb3a4279744d697b9bfe08af19ded
90
+ :target: https://www.codacy.com/gh/arkottke/pystrata/dashboard
91
+ .. |Test Coverage| image:: https://app.codacy.com/project/badge/Coverage/6dbbb3a4279744d697b9bfe08af19ded
92
+ :target: https://www.codacy.com/gh/arkottke/pystrata/dashboard
93
93
  .. |License| image:: https://img.shields.io/badge/license-MIT-blue.svg
94
94
  .. |Zenodo| image:: https://zenodo.org/badge/8959678.svg
95
95
  :target: https://zenodo.org/badge/latestdoi/8959678
96
96
  .. |MyBinder| image:: https://mybinder.org/badge_logo.svg
97
- :target: https://mybinder.org/v2/gh/arkottke/pystrata/master?filepath=examples
98
-
97
+ :target: https://mybinder.org/v2/gh/arkottke/pystrata/main?filepath=examples
99
98
 
100
99
  History
101
100
  =======
102
101
 
102
+ v0.5.2 (2023-01-18)
103
+ -------------------
104
+ - Fixed: Providing unsmoothed transfer function output
105
+ - Fixed: MenqSoilType
106
+
107
+ v0.5.1 (2022-09-22)
108
+ -------------------
109
+ - Fixed: Correlation model from Toro. Previously used rho_0 instead of d_0, and the
110
+ wrong depth
111
+ - Renamed: BedrockDepthVariation to HalfSpaceDepthVariation
112
+ - Fixed: HalfSpaceDepthVariation was removing the last layer
113
+
103
114
  v0.5.0 (2022-06-14)
104
115
  -------------------
105
116
  - Renamed to `pyStrata`.
@@ -0,0 +1,26 @@
1
+ AUTHORS.rst
2
+ HISTORY.rst
3
+ LICENSE
4
+ MANIFEST.in
5
+ README.rst
6
+ requirements.txt
7
+ setup.cfg
8
+ setup.py
9
+ pystrata/__init__.py
10
+ pystrata/motion.py
11
+ pystrata/output.py
12
+ pystrata/propagation.py
13
+ pystrata/site.py
14
+ pystrata/tools.py
15
+ pystrata/variation.py
16
+ pystrata.egg-info/PKG-INFO
17
+ pystrata.egg-info/SOURCES.txt
18
+ pystrata.egg-info/dependency_links.txt
19
+ pystrata.egg-info/top_level.txt
20
+ tests/__init__.py
21
+ tests/motion_test.py
22
+ tests/notebooks_test.py
23
+ tests/output_test.py
24
+ tests/propagation_test.py
25
+ tests/site_test.py
26
+ tests/variation_test.py
@@ -1,11 +1,13 @@
1
1
  --index-url https://pypi.python.org/simple/
2
2
 
3
3
  matplotlib
4
- numpy
5
4
  numba
5
+ numpy
6
+ pandas
6
7
  pyexcel
7
8
  pyexcel-xlsx
8
9
  pykooh
9
10
  pyrvt
10
11
  scipy
11
12
  setuptools
13
+ tomli
@@ -0,0 +1,37 @@
1
+ [metadata]
2
+ name = pystrata
3
+ version = attr: pystrata.__version__
4
+ description = Site response analysis with Python
5
+ description_file = README.rst
6
+ long_description = file: README.rst, HISTORY.rst
7
+ author = Albert R. Kottke
8
+ author_email = albert.kottke@gmail.com
9
+ license = MIT
10
+ url = https://github.com/arkottke/pystrata
11
+
12
+ [options]
13
+ packages = find:
14
+
15
+ [aliases]
16
+ test = pytest
17
+
18
+ [flake8]
19
+ exclude = docs/
20
+
21
+ [yapf]
22
+ based_on_style = pep8
23
+ spaces_around_power_operator = true
24
+
25
+ [tool:test]
26
+ addopts = --flake8
27
+
28
+ [wheel]
29
+ universal = 1
30
+
31
+ [pydocstyle]
32
+ ignore = D100,D101,D102,D103,D104,W503
33
+
34
+ [egg_info]
35
+ tag_build =
36
+ tag_date = 0
37
+
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/python3
2
+ # -*- coding: utf-8 -*-
3
+ from setuptools import setup
4
+
5
+ if __name__ == "__main__":
6
+ setup()
File without changes
@@ -77,7 +77,7 @@ def test_ts_fft_with_tf(tsm):
77
77
  def test_ts_fa_normalize(tsm):
78
78
  """Test the normalization of the Fourier amplitudes with Parsevla's theorem."""
79
79
  assert_allclose(
80
- trapz(tsm.accels ** 2, dx=tsm.time_step),
80
+ trapz(tsm.accels**2, dx=tsm.time_step),
81
81
  2 * trapz(np.abs(tsm.fourier_amps) ** 2, tsm.freqs),
82
82
  )
83
83
 
@@ -38,7 +38,7 @@ def test_notebook(fpath):
38
38
  with fpath.open() as fp:
39
39
  nb = nbformat.read(fp, as_version=4)
40
40
 
41
- ep = ExecutePreprocessor(timeout=600)
41
+ ep = ExecutePreprocessor(timeout=600, kernel_name="python3")
42
42
 
43
43
  try:
44
44
  ep.preprocess(nb, {"metadata": {"path": fpath.parent}})
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env python
2
2
  # encoding: utf-8
3
-
4
3
  # This program is free software; you can redistribute it and/or modify
5
4
  # it under the terms of the GNU General Public License as published by
6
5
  # the Free Software Foundation; either version 2 of the License, or
@@ -16,10 +15,8 @@
16
15
  # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
16
  #
18
17
  # Copyright (C) Albert Kottke, 2013-2016
19
-
20
18
  import numpy as np
21
19
  import pytest
22
-
23
20
  from numpy.testing import assert_allclose
24
21
 
25
22
  import pystrata
@@ -294,7 +294,9 @@ class TestExample02LE(DeepSoilComparison):
294
294
  pystrata.site.SoilType("Soil", 20.0, mod_reduc=None, damping=0), 20, 500
295
295
  ),
296
296
  pystrata.site.Layer(
297
- pystrata.site.SoilType("Rock", 25.0, mod_reduc=None, damping=0.02), 0, 760
297
+ pystrata.site.SoilType("Rock", 25.0, mod_reduc=None, damping=0.02),
298
+ 0,
299
+ 760,
298
300
  ),
299
301
  ]
300
302
  )
@@ -310,7 +312,9 @@ class TestExample02EL(DeepSoilComparison):
310
312
  pystrata.site.SoilType("Soil", 20.0, mod_reduc=None, damping=0), 20, 500
311
313
  ),
312
314
  pystrata.site.Layer(
313
- pystrata.site.SoilType("Rock", 25.0, mod_reduc=None, damping=0.02), 0, 760
315
+ pystrata.site.SoilType("Rock", 25.0, mod_reduc=None, damping=0.02),
316
+ 0,
317
+ 760,
314
318
  ),
315
319
  ]
316
320
  )
@@ -322,10 +326,14 @@ class TestExample04EL(DeepSoilComparison):
322
326
  profile = pystrata.site.Profile(
323
327
  [
324
328
  pystrata.site.Layer(
325
- pystrata.site.SoilType("Soil", 20.0, mod_reduc=None, damping=0.05), 20, 500
329
+ pystrata.site.SoilType("Soil", 20.0, mod_reduc=None, damping=0.05),
330
+ 20,
331
+ 500,
326
332
  ),
327
333
  pystrata.site.Layer(
328
- pystrata.site.SoilType("Rock", 25.0, mod_reduc=None, damping=0.02), 0, 760
334
+ pystrata.site.SoilType("Rock", 25.0, mod_reduc=None, damping=0.02),
335
+ 0,
336
+ 760,
329
337
  ),
330
338
  ]
331
339
  )
@@ -27,6 +27,26 @@ from . import FPATH_DATA
27
27
  from pystrata import site
28
28
 
29
29
 
30
+ def test_published_nonlinear_property():
31
+ site.NonlinearProperty.from_published("Vucetic & Dobry (91), PI=0", "damping")
32
+
33
+
34
+ def test_published_soiltype_same():
35
+ model = "Vucetic & Dobry (91), PI=0"
36
+
37
+ st = site.SoilType.from_published("test", 14, model)
38
+ assert st.mod_reduc.name == model
39
+
40
+
41
+ def test_published_soiltype_same():
42
+ model_mr = "Vucetic & Dobry (91), PI=0"
43
+ model_d = "Vucetic & Dobry (91), PI=15"
44
+
45
+ st = site.SoilType.from_published("test", 14, model_mr, model_d)
46
+ assert st.mod_reduc.name == model_mr
47
+ assert st.damping.name == model_d
48
+
49
+
30
50
  @pytest.fixture
31
51
  def nlp():
32
52
  """Create an example NonlinearProperty."""
@@ -16,7 +16,10 @@
16
16
  #
17
17
  # Copyright (C) Albert Kottke, 2013-2016
18
18
  import numpy as np
19
+ import pytest
19
20
  from numpy.testing import assert_allclose
21
+ from scipy.stats import lognorm
22
+ from scipy.stats import norm
20
23
  from scipy.stats import pearsonr
21
24
 
22
25
  from pystrata import motion
@@ -144,17 +147,26 @@ class TestSpidVariation:
144
147
  )
145
148
 
146
149
 
147
- def test_iter_variations():
148
- m = motion.SourceTheoryRvtMotion(6.0, 30, "wna")
149
- m.calc_fourier_amps()
150
-
151
- profile = site.Profile(
150
+ @pytest.fixture
151
+ def profile():
152
+ """Simple profile for tests."""
153
+ return site.Profile(
152
154
  [
155
+ site.Layer(
156
+ site.DarendeliSoilType(18.0, plas_index=0, ocr=1, stress_mean=200),
157
+ 10,
158
+ 300,
159
+ ),
153
160
  site.Layer(
154
161
  site.DarendeliSoilType(18.0, plas_index=0, ocr=1, stress_mean=200),
155
162
  10,
156
163
  400,
157
164
  ),
165
+ site.Layer(
166
+ site.DarendeliSoilType(18.0, plas_index=0, ocr=1, stress_mean=200),
167
+ 10,
168
+ 500,
169
+ ),
158
170
  site.Layer(
159
171
  site.DarendeliSoilType(18.0, plas_index=0, ocr=1, stress_mean=200),
160
172
  20,
@@ -164,6 +176,32 @@ def test_iter_variations():
164
176
  ]
165
177
  )
166
178
 
179
+
180
+ @pytest.mark.parametrize("dist", [norm(scale=2, loc=50), lognorm(s=0.2, scale=50)])
181
+ def test_halfspace_depth_variation(dist, profile):
182
+ varier = variation.HalfSpaceDepthVariation(dist)
183
+ count = 500
184
+
185
+ varied = varier(profile)
186
+ # Check the surface and bedrock is the same
187
+ assert profile[0] == varied[0]
188
+ assert profile[-1] == varied[-1]
189
+
190
+ for _ in range(10):
191
+ v = varier(profile)
192
+ assert all(layer.thickness >= 0 for layer in v)
193
+
194
+ # Sample to the half-space from the varied profiles
195
+ depths = [varier(profile)[-1].depth for _ in range(count)]
196
+
197
+ assert_allclose(dist.mean(), np.mean(depths), rtol=0.2)
198
+ assert_allclose(dist.std(), np.std(depths), rtol=0.2)
199
+
200
+
201
+ def test_iter_variations(profile):
202
+ m = motion.SourceTheoryRvtMotion(6.0, 30, "wna")
203
+ m.calc_fourier_amps()
204
+
167
205
  calc = propagation.EquivalentLinearCalculator()
168
206
  var_thickness = variation.ToroThicknessVariation()
169
207
  var_velocity = variation.ToroVelocityVariation.generic_model("USGS C")
@@ -1,27 +0,0 @@
1
- AUTHORS.rst
2
- HISTORY.rst
3
- LICENSE
4
- MANIFEST.in
5
- README.rst
6
- requirements.txt
7
- setup.cfg
8
- setup.py
9
- pyStrata.egg-info/PKG-INFO
10
- pyStrata.egg-info/SOURCES.txt
11
- pyStrata.egg-info/dependency_links.txt
12
- pyStrata.egg-info/requires.txt
13
- pyStrata.egg-info/top_level.txt
14
- pystrata/__init__.py
15
- pystrata/motion.py
16
- pystrata/output.py
17
- pystrata/propagation.py
18
- pystrata/site.py
19
- pystrata/tools.py
20
- pystrata/variation.py
21
- tests/__init__.py
22
- tests/test_motion.py
23
- tests/test_notebooks.py
24
- tests/test_output.py
25
- tests/test_propagation.py
26
- tests/test_site.py
27
- tests/test_variation.py
@@ -1,10 +0,0 @@
1
- matplotlib
2
- numpy
3
- pyrvt
4
- pykooh
5
- scipy
6
- setuptools
7
- typing
8
-
9
- [dataframe]
10
- pandas
pyStrata-0.5.0/setup.cfg DELETED
@@ -1,26 +0,0 @@
1
- [aliases]
2
- test = pytest
3
-
4
- [flake8]
5
- exclude = docs/
6
-
7
- [metadata]
8
- description-file = README.rst
9
-
10
- [yapf]
11
- based_on_style = pep8
12
- spaces_around_power_operator = true
13
-
14
- [tool:test]
15
- addopts = --flake8
16
-
17
- [wheel]
18
- universal = 1
19
-
20
- [pydocstyle]
21
- ignore = D100,D101,D102,D103,D104,W503
22
-
23
- [egg_info]
24
- tag_build =
25
- tag_date = 0
26
-
pyStrata-0.5.0/setup.py DELETED
@@ -1,48 +0,0 @@
1
- #!/usr/bin/python3
2
- # -*- coding: utf-8 -*-
3
- from setuptools import find_packages
4
- from setuptools import setup
5
-
6
- with open("README.rst") as fp:
7
- readme = fp.read()
8
-
9
- with open("HISTORY.rst") as fp:
10
- history = fp.read()
11
-
12
- setup(
13
- name="pyStrata",
14
- version="0.5.0",
15
- description="Site Response Analysis with Python",
16
- long_description=readme + "\n\n" + history,
17
- long_description_content_type='text/x-rst',
18
- author="Albert Kottke",
19
- author_email="albert.kottke@gmail.com",
20
- url="http://github.com/arkottke/pystrata",
21
- packages=find_packages(),
22
- install_requires=[
23
- "matplotlib",
24
- "numpy",
25
- "pyrvt",
26
- "pykooh",
27
- "scipy",
28
- "setuptools",
29
- "typing",
30
- ],
31
- extras_require={
32
- "dataframe": ["pandas"],
33
- },
34
- keywords="site response",
35
- license="MIT",
36
- classifiers=[
37
- "Development Status :: 4 - Beta",
38
- "Environment :: Console",
39
- "License :: OSI Approved :: MIT License",
40
- "Natural Language :: English",
41
- "Operating System :: OS Independent",
42
- "Programming Language :: Python",
43
- "Programming Language :: Python :: 3.6",
44
- "Topic :: Scientific/Engineering",
45
- "Intended Audience :: Science/Research",
46
- ],
47
- test_suite="tests",
48
- )
File without changes
File without changes
File without changes
File without changes