# ucla_geotech_tools

This ucla_geotech_tools module contains software tools developed by the UCLA geotechnical engineering group. It consists of the following packages:

* [`auto_fchp`](#auto_fchp)
* [`response_spectrum`](#response_spectrum)
* [`ipyconsol`](#ipyconsol)
* ['random_field'](#random_field)

## Installation  

To install the ucla_geotech_tools module
```python
pip install ucla_geotech_tools
```

To install a package from the module (e.g., auto_fchp)
```python
pip install ucla_geotech_tools.auto_fchp
```

## auto_fchp

Return the high-pass corner frequency value that stabilizes the displacement of a ground motion record.

The high-pass corner frequency, *f<sub>chp</sub>*, is selected to satisfy two objectives:
1. The amplitude of a polynomial fit to the filtered displacement record divided by the amplitude of the filtered displacement record is within a tolerance of a specified target.
2. The amplitude of the initial portion of the displacement record before the p-wave arrival divided bythe amplitude of the filtered displacement record is within a tolerance of a specified target.

The value of *f<sub>chp</sub>* is computed numerically using the Scipy package scipy.optimize.ridder(). Two initial values of *f<sub>chp</sub>* are provided that bracket the root, and the Scipy package solves for the root that minimizes the objective function. The tolerance is on the value of *f<sub>chp</sub>*, not on the value of the residual (i.e., xtol in optimize.ridder).

A value of *f<sub>chp</sub>* is obtained first to satisfy objective 1. Objective 2 is optional, and if it is applied, the value of *f<sub>chp</sub>* from objective 1 is checked against objective 2. If the residual from objective 2 is less than or equal to zero, *f<sub>chp</sub>* is set equal to the value from objective 1. Otherwise, iterations are performed to satisfy objective 2.

### Functions

#### get_fchp(**kwargs)

Return the high-pass corner frequency

Keyword Args:
* *```dt``` : time step in seconds (float, required)
* *```acc``` : acceleration array in L/s/s, where L is length (Numpy array dtype=float, required)
* ```target```: desired ratio of polynomial fit amplitude to displacement amplitude (default=0.02)
* ```tol```: tolerance for fchp (default=0.001)
* ```poly_order```: order of polynomial to fit to filtered displacement record (default=6)
* ```maxiter```: maximum number of iterations (default=30)
* ```fchp_min```: minimum frequency in Hz to consider for fchp (default=0.001)
* ```fchp_max```: maximum frequency in Hz to consider for fchp (default=0.5)
* ```tukey_alpha```: alpha parameter for scipy.signal.windows.tukey (default=0.05)
* ```apply_disp_ratio```: flag to indicate whether to apply objective 2 (default=0)
* ```disp_ratio_time```: duration in seconds of the initial portion of the record before the p-wave arrival (default=30)
* ```disp_ratio_target```: target ratio of amplitude of initial portion of displacement record to amplitude of displacement record

#### get_residual1(fchp, *args):

Return the residual defined as disp_fit/disp_filt - target.

Args:
* ```fchp```: High-pass corner frequency (float)
* ```Fdisp```: Fourier coefficients of displacement record (Numpy array, dtype=complex)
* ```time``` = time values (Numpy array, dtype=float)
* ```poly_order``` = Order of polynomial to fit to filtered displacement (float)
* ```target``` = Desired ratio of polynomial fit amplitude to displacement signal amplitude (float)
* ```freq``` = Numpy array containing frequency values

Computed variables:
* ```filt``` = Coefficients of 5th order Butterworth filter
* ```Fdisp_filt``` = Numpy array containing Fourier coefficients of filtered displacement record
* ```disp_filt``` = Numpy array containing filtered displacement record
* ```coef``` = Coefficients of polynomial fit to displacement record
* ```disp_fit``` = Numpy array containing polynomial fit ordinates at each time


#### get_residual2(fchp, *args):
    
Returns the residual defined as disp_init/disp - target.

Args:
* ```fchp``` = High-pass corner frequency
* ```Fdisp``` = Numpy array containing Fourier coefficients of displacement record
* ```time``` = Numpy array containing time values
* ```disp_time``` = Duration of initial portion of record before p-wave arrival
* ```disp_target``` = Desired ratio of amplitude of initial portion of displacement record to amplitude of displacement record
* ```freq``` = Numpy array containing frequency values

Computed variables:
* ```filt``` = Coefficients of 5th order Butterworth filter
* ```Fdisp_filt``` = Numpy array containing Fourier coefficients of filtered displacement record
* ```disp_filt``` = Numpy array containing filtered displacement record

## response_spectrum

response_spectrum computes a psuedo-acceleration response spectrum from an input ground motion or set of ground motions sampled at a constant frequency. Calculates are performed in the frequency domain by

1. taking the Fourier transform of the input motion(s)
2. multiplying by the transfer function for computing the motion of a single-degree-of-freedom (SDOF) oscillator with natural period T and damping D
3. computing the peak acceleration amplitude for the SDOF oscillator
4. repeating steps 2 and 3 for a range of user-specified periods

### Functions

#### get_response_spectrum(**kwargs)

Returns a Numpy array containing response spectra

Keyword Args:
* *```motions``` = Numpy array (M x N) containing acceleration data, where M is the number of motions and N is the number of data points in each motion. All motions must have the same number of data points. Python lists are not allowed; only Numpy arrays (required)  
* *```dt``` = time step in seconds (required)
* ```D``` = damping (default = 0.05)
* ```T``` = array of natural periods (default = array used for NGAwest2 project) 
* ```zeropad``` = 1: apply zero padding to speed up FFT operation, 0: do not pad with zeros (default = 1)

#### get_ngawest2_T()

Returns a Numpy array containing NGAWest2 natural periods

## ipyconsol

Documentation coming soon

## random_field

Documentation coming soon