# Class Numerical

```    Assorted, general numerical methods
```
nameargumentsreturns
curve_intersect_interpolatecls, df: pd.DataFrame, row_index :int, x, var1, var2(float, float)
```        Fine-tune the intersection point between 2 Pandas dataframe columns,
using linear interpolation

:param df:          A Pandas dataframe with at least 3 columns
:param row_index:   The index of the Pandas dataframe row
with the smallest absolute value of difference in concentrations
:param x:           The name of the dataframe column with the independent variable
:param var1:        The name of the dataframe column with the data from the 1st curve
:param var2:        The name of the dataframe column with the data from the 2nd curve
:return:            The pair (time of intersection, common value)
```
nameargumentsreturns
segment_intersectcls, t, y1, y2(float, float)
```        Find the intersection of 2 segments in 2D.
Their respective endpoints share the same x-coordinates: (t_start, t_end)

Note: for an alternate method, see line_intersect()

:param t:   Pair with the joint x-coordinates of the 2 start points,
and the joint x-coordinates of the 2 end points
:param y1:  Pair with the y_coordinates of the endpoints of the 1st segment
:param y2:  Pair with the y_coordinates of the endpoints of the 2nd segment
Note: either segment - but not both - may be horizontal

:return:    A pair with the (x,y) coord of the intersection;
if the segments don't meet their specs (which might result in the lack of an intersection),
an Exception is raised
```
nameargumentsreturns
line_intersectcls, p1, p2, q1, q2Union[tuple, None]
```        Returns the coordinates of the intersection
between the line passing thru the points p1 and p2,
and the line passing thru the points q1 and q2.

Based on https://stackoverflow.com/a/42727584/5478830

Note: for an alternate method, see segment_intersect()

:param p1:  Pair of (x,y) coord of a point on the 1st line
:param p2:  Pair of (x,y) coord of another point on the 1st line
:param q1:  Pair of (x,y) coord of a point on the 2nd line
:param q2:  Pair of (x,y) coord of another point on the 2nd line

:return:    A pair with the (x,y) coord of the intersection, if it exists;
or None if it doesn't exist
```
nameargumentsreturns
deep_flattencls, itemslist
```        Completely flatten any lists/tuples of lists or tuples
into a single list
EXAMPLES:
[[1,2,3], [4,5,6], , [8,9]] becomes [1, 2, 3, 4, 5, 6, 7, 8, 9]
(1,2)                       becomes [1,2]
[(1, 2), (3,4)]             becomes [1, 2, 3, 4]
5                           becomes 
"hello"                     becomes ["hello"]

:param items:   A list or tuple possibly containing lists or tuples
:return:        A flat list
```
nameargumentsreturns
compare_resultscls, res1, res2float
```        Use a Euclidean distance metric to compare 2 sets of results - typically from 2 runs
of different accuracy.
Each result value may be a number or a list or tuple, possibly containing lists or tuples,
of numbers.
However, after the structure is flattened,
the 2 result data sets must have the same number of points

:param res1:
:param res2:
:return:    The distance between the two sets of value, based on an L2 (Euclidean) metric
```
nameargumentsreturns
compare_vectorscls, v1: np.array, v2: np.array, metric=None, trim_edges=0float
```        Return the Euclidean distance between the two given same-sized Numpy arrays
(TODO: offer option to use alternate metrics)

:param v1:
:param v2:
:param metric:      NOT YET USED: the default L2 norm is always used
:param trim_edges:  (OPTIONAL) number of elements to ditch at each end,
prior to comparing the vectors (default: 0)
:return:            The distance between the two vectors based on an L2 (Euclidean) metric
```
nameargumentsreturns
compare_statescls, state1: np.array, state2: np.array, verbose=FalseNone
```        Print out various assessments of how similar two same-sized Numpy arrays are.
Typically, those arrays will be system state snapshots - but could be anything.

:param state1:
:param state2:
:param verbose: If True, additional output is shown
:return:        None
```
nameargumentsreturns
```        Compute the gradient, from the values in the given array,
using the 5-point Central Difference, which produces an accuracy of order 4.

At the boundary, or close to it, different 5-point stencils are used,
still resulting in an accuracy of order 4.
For the coefficients, see: https://web.media.mit.edu/~crtaylor/calculator.html

Returns the same size as the input array.

For a simpler, but less accurate (order 2) approach, simply use Numpy gradient()

:param arr:     One-dimensional Numpy array (or list, or tuple) of numbers,
with at least 5 elements
:param dx:      Delta_x (assumed constant)
:param dtype:   Data type to use for the elements of the returned array

:return:        A Numpy array with the same size as the one passed in arr
```
nameargumentsreturns
```        Compute the gradient, from the values in the given (possibly multidimensional) array,
using the 5-point Central Difference, which produces an accuracy of order 4.

At the boundary, and at the points immediately adjacent to the boundary,
simple 2-point forward or backward differences are used (accuracy order 1.)

It returns a list of ndarrays (or a single ndarray if there is only 1 dimension).
Each list element has the same shape as the original array,
and corresponds to the derivatives of the passed array with respect to each dimension.

For 1-dimensional cases, can also use gradient_order4_1d(), which produces accuracy order 4 at ALL points.

(ADAPTED FROM https://gist.github.com/deeplycloudy/1b9fa46d5290314d9be02a5156b48741 , which is
based on 2nd order version from http://projects.scipy.org/scipy/numpy/browser/trunk/numpy/lib/function_base.py

:param f:       An N-dimensional array giving samples of a scalar function
:param varargs: 0, 1, or N scalars giving the sample distances in each direction

:return:        A list of N numpy arrays,
each of the same shape as f giving the derivative of f with respect to each dimension
```
nameargumentsreturns
expand_matrix_boundarycls, mnp.array
```        Add a row at the top and at the bottom, and also add a column to the left and to the right,
repeating the edge values of the matrix
EXAMPLE:  [[1, 2],
[3, 4]]
will turn to
[[1, 1, 2, 2],
[1, 1, 2, 2],
[3, 3, 4, 4],
[3, 3, 4, 4]]
Note how the original matrix is "embedded" in the center of the larger one

:param m:   A Numpy matrix
:return:    A Numpy matrix, with 2 extra rows (at top and bottom) and 2 extra columns (at left and right)
```