コード例 #1
0
def Ewer_Basu__B_z(r, z, h, k_array, disk_radius, uniform_B0):
    """
    This implements equation 46 of Ewertiwski & Basu 2013. The k_array (values
    of k) determine the number of summation terms that will be computed.
    """
    # Type check
    r = valid.validate_float_array(r)
    z = valid.validate_float_array(z)
    k_array = valid.validate_float_array(k_array, deep_validate=True)
    disk_radius = valid.validate_float_value(disk_radius, greater_than=0)
    uniform_B0 = valid.validate_float_value(uniform_B0)

    # Shorthand for the squareroot of the eigenvalues. Account for 0 indexing.
    def evsq(m):
        return np.sqrt(Ewer_Basu__eigenvalues(m + 1, disk_radius))

    # Shorthand for bessel function of order 1.
    def bess0(x):
        return sp_spcl.jv(0, x)

    Bfeild_z = 0
    for kdex, k_value in enumerate(k_array):
        # Dividing the equation into smaller chunks for readability.
        coefficient = k_value * evsq(kdex) * bess0(evsq(kdex) * r)
        # Left and right erfc functions of the equation, respectively.
        plus_erfc = sp_spcl.erfc((0.5 * evsq(kdex) * h) + z / h)
        minus_erfc = sp_spcl.erfc((0.5 * evsq(kdex) * h) - z / h)
        # Exponent values
        pos_exp = np.exp(evsq(kdex) * z)
        neg_exp = np.exp(-evsq(kdex) * z)

        Bfeild_z = (Bfeild_z + (coefficient *
                                (plus_erfc * pos_exp + minus_erfc * neg_exp)))

    return Bfeild_z + uniform_B0
コード例 #2
0
def generate_noisy_gaussian(center, std_dev, height, x_domain, noise_domain,
                            n_datapoints):
    """
    Generate a gaussian with some aspect of noise.

    Input:
        center = central x value
        std_dev = standard deviation of the function
        height = height (y-off set) of the function
        noise_range = uniform random distribution of noise from perfect gauss function
        x_range = absolute domain of the gaussian function 
        n_datapoints = total number of input datapoints of gaussian function
    Output: x_values,y_values
        x_values = the x-axial array of the gaussian function within the domain
        y_values = the y-axial array of the gaussian function within the domain
    """
    # Type check.
    center = valid.validate_float_value(center)
    std_dev = valid.validate_float_value(std_dev, greater_than=0)
    height = valid.validate_float_value(height)
    x_domain = valid.validate_float_array(x_domain, shape=(2,), size=2)
    noise_domain = valid.validate_float_array(noise_domain, shape=(2,), size=2)
    n_datapoints = valid.validate_int_value(n_datapoints, greater_than=0)

    # Generate the gaussian function and map to an output with the input
    # parameters.
    x_values, y_values = generate_gaussian(center, std_dev, height,
                                           x_domain=x_domain,
                                           n_datapoints=n_datapoints)

    # Imbue the gaussian with random noise.
    y_values = misc.generate_noise(y_values, noise_domain,
                                   distribution='uniform')

    return x_values, y_values
コード例 #3
0
def hourglass_magnetic_field_cyln(
        r,
        phi,
        z,  # Cylindrical cords
        h,
        k_array,
        disk_radius,
        uniform_B0):
    """
    This function retruns the magnitude of an hourglass magnetic field in
    cylindrical cords given a location in cylindrical cords.
    """

    # Type check
    r = valid.validate_float_array(r, greater_than=0)
    phi = valid.validate_float_array(phi,
                                     deep_validate=True,
                                     greater_than=0,
                                     less_than=2 * np.pi)
    z = valid.validate_float_array(z)
    h = valid.validate_float_value(h)
    k_array = valid.validate_float_array(k_array, deep_validate=True)
    disk_radius = valid.validate_float_value(disk_radius, greater_than=0)
    uniform_B0 = valid.validate_float_value(uniform_B0)

    # The phi component of the field is agnostic as the values of the magnetic
    # field is independent of phi, see equation 3 and 4 in Ewertiwski & Basu
    # 2013
    B_r = Ewer_Basu__B_r(r, z, h, k_array, disk_radius)
    B_phi = 0
    B_z = Ewer_Basu__B_z(r, z, h, k_array, disk_radius, uniform_B0)

    return B_r, B_phi, B_z
コード例 #4
0
def Ewer_Basu__eigenvalues(index_m, radius):
    """
    This is the values of the eigenvalues of some integer index m as it
    pertains to Ewertiwski & Basu 2013.
    """
    # Type check.
    index_m = valid.validate_int_value(index_m, greater_than=0)
    radius = valid.validate_float_value(radius)

    eigenvalue = (bessel_zeros(1, index_m) / radius)**2

    return valid.validate_float_value(eigenvalue)
コード例 #5
0
def bessel_function_2nd(x_input, order):
    """
    This is a wrapper function around scipy's bessel function of the
    second kind, given any real order value. This wrapper also includes
    input verification.

    Input:
    x_input = The x value input of the bessel function.
    order = The value(s) of orders wanting to be computed.
    center = The x displacement from center (i.e. the new center)
    height = The y displacement from center (i.e. the new height offset)

    Output:
    y_output = The y value(s) from the bessel function.
    """

    # Type check.
    x_input = valid.validate_float_array(x_input)
    if isinstance(order, (float, int)):
        order = valid.validate_float_value(order)
    else:
        order = valid.validate_float_array(order, deep_validate=True)

    # Compute the value(s) of the bessel_function
    y_output = sp_spcl.yv(order, x_input)

    return np.array(y_output, dtype=float)
コード例 #6
0
def bessel_function_1st(x_input, order):
    """
    This is a wrapper function around scipy's bessel function of the
    first kind, given any real order value. This wrapper also includes
    input verification.

    Input:
    x_input = The x value input of the bessel function.
    order = The value(s) of orders wanting to be computed.

    Output:
    y_output = The y value(s) from the bessel function.
    """

    # Type check.
    x_input = valid.validate_float_array(x_input)
    if isinstance(order, (float, int)):
        order = valid.validate_float_value(order)
    else:
        order = valid.validate_float_array(order, deep_validate=True)

    # Compute the value(s) of the bessel_function
    y_output = sp_spcl.jv(order, x_input)

    return np.array(y_output, dtype=float)
コード例 #7
0
def cloud_line_integral(field_function,
                        cloud_equation,
                        view_line_point,
                        box_width,
                        view_line_deltas=(1, 0, 0),
                        n_guesses=100):
    """
    This function computes the total summation of the line integrals given
    a field function that a single sightline passes through, given the 
    boundary that only the section of the line within a cloud would be 
    computed as it is the upper and lower bounds for the integral(s).
    """
    # Type check
    field_function = valid.validate_function_call(field_function,
                                                  n_parameters=3)
    cloud_equation = valid.validate_function_call(cloud_equation,
                                                  n_parameters=3)
    view_line_point = valid.validate_float_array(view_line_point, shape=(3, ))
    box_width = valid.validate_float_value(box_width, greater_than=0)
    view_line_deltas = valid.validate_tuple(view_line_deltas, length=3)
    n_guesses = valid.validate_int_value(n_guesses, greater_than=0)

    # Integrating function. Parameterize the field function to integrate over
    # the curve given by the sightline.
    # Define the sightline parametric equations.
    def x_param(t):
        return view_line_deltas[0] * t + view_line_point[0]

    def y_param(t):
        return view_line_deltas[1] * t + view_line_point[1]

    def z_param(t):
        return view_line_deltas[2] * t + view_line_point[2]

    # Assume that the user's function accepts x,y,z in that order.
    def parameterized_field_equation(t):
        return field_function(x_param(t), y_param(t), z_param(t))

    # Determine the lower and upper bounds of the parameterized functional
    # integrations.
    lower_bounds,upper_bounds = \
        line_integral_boundaries(view_line_point,cloud_equation,box_width,
                                 view_line_deltas,n_guesses)

    # The total integrated number.
    integrated_value = 0
    error = []  # Error array
    for lowerdex, upperdex in zip(lower_bounds, upper_bounds):
        integration = sp.integrate.quad(parameterized_field_equation, lowerdex,
                                        upperdex)
        integrated_value += integration[0]
        error.append(integration[1])

    # Errors add in quadrature.
    error = np.sqrt(np.dot(error, error))

    return integrated_value, error
コード例 #8
0
def gaussian_function(x_input, center, std_dev, height):
    """
    Equation for a single gaussian.

    Input:
    x_input = x-values to be input into the gaussian function.
    """

    # Type check.
    x_input = valid.validate_float_array(x_input)
    center = valid.validate_float_value(center)
    # Standard deviations can't be negative.
    std_dev = valid.validate_float_value(std_dev, greater_than=0)
    height = valid.validate_float_value(height)

    # Use the equation of a gaussian from Wikipedia:
    y_output = (((1 / (std_dev * np.sqrt(2 * np.pi)))
                 * np.exp(-0.5 * ((x_input - center)/std_dev)**2))
                + height)
    return np.array(y_output, dtype=float)
コード例 #9
0
def hourglass_magnetic_field_cart(
        x,
        y,
        z,  # Cartesian cords
        h,
        k_array,
        disk_radius,
        uniform_B0):
    """
    This function retruns the magnitude of an hourglass magnetic field in
    cartesian cords given a location in cartesian cords.
    """
    # Type check
    x = valid.validate_float_array(x)
    y = valid.validate_float_array(y)
    z = valid.validate_float_array(z)
    h = valid.validate_float_value(h)
    k_array = valid.validate_float_array(k_array, deep_validate=True)
    disk_radius = valid.validate_float_value(disk_radius, greater_than=0)
    uniform_B0 = valid.validate_float_value(uniform_B0)

    # Convert to cylindrical cords.
    r = np.hypot(x, y)
    phi = np.arctan2(y, x)
    z = z

    # Find the values of the magnetic field.
    B_r, B_phi, B_z = \
        hourglass_magnetic_field_cyln(r, phi, z,
                                      h, k_array, disk_radius, uniform_B0)

    # Convert to cartesian.
    B_x = B_r * np.cos(phi)
    B_y = B_r * np.sin(phi)
    B_z = B_z

    # Return cartesian
    return B_x, B_y, B_z
コード例 #10
0
def fit_bessel_function_2nd(x_points,
                            y_points,
                            order_guess=None,
                            order_bounds=None):
    """
    This function returns the order of a Bessel function of the second kind 
    that fits the data points according to a least squares fitting algorithm.

    Input:
    x_points = The x values of the points to fit.
    y_points = The y values of the points to fit.
    order_guess = A starting point for order guessing.
    order_bounds = The min and max values the order can be.

    Output:
    fit_order = The value of the order of the fit bessel function.
    """
    # The total number of points, useful.
    n_datapoints = len(x_points)
    n_datapoints = valid.validate_int_value(n_datapoints, greater_than=0)
    if (n_datapoints <= 1):
        raise InputError('It does not make sense to fit one or less points.'
                         '    --Kyubey')

    # Type check
    x_points = valid.validate_float_array(x_points, size=n_datapoints)
    y_points = valid.validate_float_array(y_points, size=n_datapoints)
    if (order_guess is not None):
        order_guess = valid.validate_float_value(order_guess)
    else:
        order_guess = 1
    if (order_bounds is not None):
        order_bounds = valid.validate_float_array(order_bounds,
                                                  shape=(2, ),
                                                  size=2)
    else:
        order_bounds = (-np.inf, np.inf)

    # Function fitting, Scipy's module is likely the better method to go.
    fit_parameters = sp_opt.curve_fit(bessel_function_2nd,
                                      x_points,
                                      y_points,
                                      p0=order_guess,
                                      bounds=order_bounds)

    # Split the fitted order and covariance array.
    fit_order = float(fit_parameters[0])
    covariance = float(fit_parameters[1])

    return fit_order, covariance
コード例 #11
0
def bessel_zeros(order, n_zero):
    """
    These are the positive zeros of the bessel functions. 
    This function returns the nth zero of a bessel function based on the order.
    """

    # Type check.
    order = valid.validate_int_value(order, greater_than=0)
    n_zero = valid.validate_int_value(n_zero, greater_than=0)

    # For some reason, scipy wants to return all zeros from 1 to n. This
    # function only wants the last one.
    zeros = sp_spcl.jn_zeros(order, n_zero)
    return valid.validate_float_value(zeros[-1])
コード例 #12
0
def Stokes_parameter_polarization_angle(Q, U):
    """
    This function returns an angle of polarization in radians based on the 
    values of two stoke parameters. The angle is signed.
    """

    # Type check
    Q = valid.validate_float_array(Q)
    U = valid.validate_float_value(U)

    # Based off of Wikipedia and computational testing
    angle = 0.5 * np.arctan2(U, Q)

    return angle
コード例 #13
0
def generate_noisy_bessel_1st(order,
                              x_domain,
                              noise_domain,
                              n_datapoints,
                              distribution='uniform'):
    """
    This function generates a noisy bessel function of the first kind given
    a real order.

    Input:
    order = The real order of the bessel function
    x_domain = The range of x_values that should be plotted.
    noise_domain = The domain the noise is allowed to spread around.
    n_datapoints = The number of data points that is desired.
    distribution = The method of noise distribution.

    Output:
    y_output = The values of the function after noise.    
    """

    # Type check.
    order = valid.validate_float_value(order)
    x_domain = valid.validate_float_array(x_domain, shape=(2, ), size=2)
    noise_domain = valid.validate_float_array(noise_domain,
                                              shape=(2, ),
                                              size=2)
    distribution = valid.validate_string(distribution)

    # Generate the input values. Make sure the first element is the lower
    # element.
    x_domain = np.sort(x_domain)
    x_input = np.random.uniform(x_domain[0], x_domain[-1], n_datapoints)

    # Generate values for the bessel function.
    y_output = bessel_function_1st(x_input, order)

    # Imbue the values with noise.
    y_output = misc.generate_noise(y_output,
                                   noise_domain,
                                   distribution=distribution)

    # Sort the values for ease of plotting and computation.
    sort_index = np.argsort(x_input)
    x_input = x_input[sort_index]
    y_output = y_output[sort_index]

    return np.array(x_input, dtype=float), np.array(y_output, dtype=float)
コード例 #14
0
def generate_noisy_dual_dimension_gaussian(centers,
                                           std_devs,
                                           height,
                                           n_datapoints,
                                           x_domain,
                                           y_domain,
                                           noise_domain,
                                           dimensions=2):
    """
    This generates a noisy 2D gaussian.
    """

    # Type check
    dimensions = valid.validate_int_value(dimensions, greater_than=0)
    centers = valid.validate_float_array(centers,
                                         shape=(dimensions, ),
                                         size=dimensions)
    std_devs = valid.validate_float_array(std_devs,
                                          shape=(dimensions, ),
                                          size=dimensions,
                                          deep_validate=True,
                                          greater_than=0)
    height = valid.validate_float_value(height)
    n_datapoints = valid.validate_int_value(n_datapoints, greater_than=0)
    x_domain = valid.validate_float_array(x_domain, shape=(2, ), size=2)
    y_domain = valid.validate_float_array(y_domain, shape=(2, ), size=2)
    noise_domain = valid.validate_float_array(noise_domain,
                                              shape=(2, ),
                                              size=2)

    # Generate the 2D gaussian.
    points = generate_dual_dimension_gaussian(centers, std_devs, height,
                                              n_datapoints, x_domain, y_domain)

    # Imbue the z points (2 index) with noise.
    points[2] = misc.generate_noise(points[2], noise_domain)

    return points
コード例 #15
0
def generate_dual_dimension_gaussian(centers,
                                     std_devs,
                                     height,
                                     n_datapoints,
                                     x_domain,
                                     y_domain,
                                     dimensions=2):
    """
    This generates random points for a 2D dimensional gaussian. 
    """

    # Type check
    dimensions = valid.validate_int_value(dimensions, greater_than=0)
    centers = valid.validate_float_array(centers,
                                         shape=(dimensions, ),
                                         size=dimensions)
    std_devs = valid.validate_float_array(std_devs,
                                          shape=(dimensions, ),
                                          size=dimensions,
                                          deep_validate=True,
                                          greater_than=0)
    height = valid.validate_float_value(height)
    n_datapoints = valid.validate_int_value(n_datapoints, greater_than=0)
    x_domain = valid.validate_float_array(x_domain, shape=(2, ), size=2)
    y_domain = valid.validate_float_array(y_domain, shape=(2, ), size=2)

    # Generate x and y points at random.
    x_values = np.random.uniform(x_domain[0], x_domain[-1], size=n_datapoints)
    y_values = np.random.uniform(y_domain[0], y_domain[-1], size=n_datapoints)

    # Compile into a parallel pair of (x,y)
    input_points = np.append([x_values], [y_values], axis=0)

    # Compute the z_values, desire only the output points.
    z_values, output_points = dual_dimensional_gauss_equation(
        input_points, centers, std_devs, height, dimensions)

    return output_points
コード例 #16
0
def dual_dimensional_gauss_equation(input_points, center, std_dev, height,
                                    dimensions):
    """
    This function generates gaussians of multiple dimensions/variables given
    the center's coordinates and the covariance matrix.
    """
    try:
        n_datapoints = len(input_points[0])
    except:
        input_points = valid.validate_float_array(input_points)
        n_datapoints = len(input_points[0])

    # Validate, dimensions must go first.
    dimensions = valid.validate_int_value(dimensions, greater_than=0)
    input_points = valid.validate_float_array(input_points,
                                              shape=(2, n_datapoints))
    center = valid.validate_float_array(center,
                                        shape=(dimensions, ),
                                        size=dimensions)
    std_dev = valid.validate_float_array(std_dev,
                                         shape=(dimensions, ),
                                         size=dimensions,
                                         deep_validate=True,
                                         greater_than=0)
    height = valid.validate_float_value(height)

    # For two dimensions.
    normalization_term = 1 / (2 * np.pi * std_dev[0] * std_dev[1])

    exp_x_term = (input_points[0] - center[0])**2 / (2 * std_dev[0]**2)
    exp_y_term = (input_points[1] - center[1])**2 / (2 * std_dev[1]**2)

    z_points = normalization_term * np.exp(-(exp_x_term + exp_y_term)) + height

    output_points = np.append(input_points, np.array([z_points]), axis=0)

    return z_points, output_points
コード例 #17
0
def fit_multigaussian(x_values, y_values,
                      gaussian_count=None,
                      window_len_ratio=0.1, sg_polyorder=3,
                      prominence=0.10,
                      *args, **kwargs):
    """
    Fit a gaussian function with 3 degrees of freedom but with many gaussians.

    Input:
        x_values = the x-axial array of the values
        y_values = the y-axial array of the values
        gaussian_count = the number of expected gaussian functions
        fft_keep = the percentage kept by the fft truncation, use a lower 
            fft_keep if there is a lot of noise
        prom_height_ratio = the ratio of prominence to height for width 
            detection, a lower value increases accuracy until there are too
            little patterns.


    Returns center_array,std_dev_array,height_array,covariance_array
        center_array = the central value of the gaussian
        std_dev_array = the standard deviation of the gaussian
        height_array = the height of the gaussian function along the x-axis
        covariance_array = a convariance matrix of the fit
    """
    # The total number of points, useful.
    try:
        n_datapoints = len(x_values)
    except:
        raise InputError('It does not make sense to try and fit a '
                         'single point.'
                         '    --Kyubey')
    else:
        n_datapoints = valid.validate_int_value(n_datapoints, greater_than=0)

    # Initial variables.
    center_array = []
    std_dev_array = []
    height_array = []
    covariance_array = []

    # Type check.
    x_values = valid.validate_float_array(x_values, size=n_datapoints)
    y_values = valid.validate_float_array(y_values, size=n_datapoints)
    if (gaussian_count is not None):
        # Gaussian count can't be less than 0.
        gaussian_count = valid.validate_int_value(
            gaussian_count, greater_than=0)
    window_len_ratio = valid.validate_float_value(window_len_ratio)
    sg_polyorder = valid.validate_int_value(sg_polyorder)
    prominence = valid.validate_float_value(prominence)

    # Implement the Savitzky-Golay filtering algorithm.
    # Window width needs to be an odd interger by Scipy and algorithm
    # stipulation.
    window_width = int(window_len_ratio * n_datapoints)
    if (window_width % 2 == 0):
        # It is even, make odd.
        window_width += 1
    elif (window_width % 2 == 1):
        # It is odd, it should be good.
        pass

    filtered_y_values = sp_sig.savgol_filter(y_values,
                                             window_width,
                                             sg_polyorder)

    # Detect possible peaks of Gaussian functions.
    peak_index, peak_properties = \
        sp_sig.find_peaks(filtered_y_values, prominence=prominence)
    left_bases = peak_properties['left_bases']
    right_bases = peak_properties['right_bases']

    # Attempt to fit a gaussian curve between the ranges of each peak.
    for peakdex, left_basedex, right_basedex in \
            zip(peak_index, left_bases, right_bases):
        # Separate each of the gaussians and try to find parameters.
        center, std_dev, height, covariance = \
            fit_gaussian(x_values[left_basedex:right_basedex],
                         y_values[left_basedex:right_basedex],
                         center_guess=x_values[peakdex])

        # Append the values to the arrays of information.
        center_array.append(center)
        std_dev_array.append(std_dev)
        height_array.append(height)
        covariance_array.append(covariance)

    # Type check before returning, just in case.
    center_array = valid.validate_float_array(center_array)
    std_dev_array = valid.validate_float_array(std_dev_array)
    height_array = valid.validate_float_array(height_array)
    covariance_array = valid.validate_float_array(covariance_array)

    return center_array, std_dev_array, height_array, covariance_array
コード例 #18
0
def fit_gaussian(x_values, y_values,
                 center_guess=None, std_dev_guess=None, height_guess=None,
                 center_bounds=None, std_dev_bounds=None, height_bounds=None):
    """
    Fit a gaussian function with 3 degrees of freedom.

    Input:
        x_values = the x-axial array of the values
        y_values = the y-axial array of the values
        center_guess = a starting point for the center
        std_dev_guess = a starting point for the std_dev
        height_guess = a starting point for the height

    Returns center,std_dev,height,covariance
        center = the central value of the gaussian
        std_dev = the standard deviation of the gaussian
        height = the height of the gaussian function along the x-axis
        covariance = a convariance matrix of the fit
    """
    # The total number of points, useful.
    try:
        n_datapoints = len(x_values)
    except:
        raise InputError('It does not make sense to try and fit a '
                         'single point.'
                         '    --Kyubey')
    else:
        n_datapoints = valid.validate_int_value(n_datapoints, greater_than=0)

    # Type check
    x_values = valid.validate_float_array(x_values)
    y_values = valid.validate_float_array(y_values)

    # Type check optional issues.
    # Type check the guesses
    if (center_guess is not None):
        center_guess = valid.validate_float_value(center_guess)
    else:
        # The default of scipy's curve fit.
        center_guess = 1
    if (std_dev_guess is not None):
        std_dev_guess = valid.validate_float_value(
            std_dev_guess, greater_than=0)
    else:
        # The default of scipy's curve fit.
        std_dev_guess = 1
    if (height_guess is not None):
        height_guess = valid.validate_float_value(height_guess)
    else:
        # The default of scipy's curve fit.
        height_guess = 1
    # Type check bounds.
    if (center_bounds is not None):
        center_bounds = valid.validate_float_array(center_bounds, size=2)
        center_bounds = np.sort(center_bounds)
    else:
        center_bounds = np.array([-np.inf, np.inf])
    if (std_dev_bounds is not None):
        std_dev_bounds = valid.validate_float_array(std_dev_bounds, size=2,
                                                    deep_validate=True,
                                                    greater_than=0)
        std_dev_bounds = np.sort(std_dev_bounds)
    else:
        std_dev_bounds = np.array([0, np.inf])
    if (height_bounds is not None):
        height_bounds = valid.validate_float_array(height_bounds)
        height_bounds = np.sort(height_bounds)
    else:
        height_bounds = np.array([-np.inf, np.inf])

    # Compiling the guesses.
    guesses = np.array([center_guess, std_dev_guess, height_guess])

    # Compiling the bounds
    lower_bounds = (center_bounds[0], std_dev_bounds[0], height_bounds[0])
    upper_bounds = (center_bounds[1], std_dev_bounds[1], height_bounds[1])
    bounds = (lower_bounds, upper_bounds)

    # Use scipy's curve optimization function for the gaussian function.
    fit_parameters, covariance = sp_opt.curve_fit(gaussian_function,
                                                  x_values, y_values,
                                                  p0=guesses, bounds=bounds)

    # For ease.
    center = fit_parameters[0]
    std_dev = fit_parameters[1]
    height = fit_parameters[2]

    return center, std_dev, height, covariance
コード例 #19
0
def generate_noise(
        input_array,
        noise_domain,
        distribution='uniform',
        center=None,
        std_dev=None,  # Normal distribution terms.
        debug=False):
    """
    Takes a set of 'perfect' datapoints and scatters them based on some 
    randomly generated noise. The generated noise can be distributed in a number
    of ways.

    Input:
    input_array = array of datapoints to be scattered from the original value
    noise_domain = (2,) shaped array of the upper and lower bounds of scattering
    distribution = method of random number distribution
                    - 'uniform'
                    - 'gaussian'
    debug = Debug mode

    Output:
    output_array = scattered 'noisy' datapoints
    """
    # Type check.
    input_array = valid.validate_float_array(input_array,
                                             size=len(input_array))
    noise_domain = valid.validate_float_array(noise_domain,
                                              shape=(2, ),
                                              size=2)
    distribution = valid.validate_string(distribution)

    # Initial conditions
    n_datapoints = len(input_array)

    # Ensure the lower bound of the noise domain is the first element.
    if (noise_domain[0] < noise_domain[-1]):
        # This is correct behavior.
        pass
    elif (noise_domain[0] > noise_domain[-1]):
        # Warn and change, the array seems to be reversed.
        noise_domain = np.flip(noise_domain, axis=0)
    elif (noise_domain[0] == noise_domain[-1]):
        raise ValueError('Noise domain range is detected to be zero. There is '
                         'no functional use of this function.    --Kyubey')

    # Check for distribution method, generate noise array from method.
    if (distribution == 'uniform'):
        if (debug):
            print('Noise distribution set to "uniform".')
        noise_array = np.random.uniform(noise_domain[0],
                                        noise_domain[1],
                                        size=n_datapoints)
    elif ((distribution == 'gaussian') or (distribution == 'normal')):
        if (debug):
            print('Noise distribution set to "gaussian".')
            kyubey_warning(OutputWarning,
                           ('Noise domain is ignored under '
                            'gaussian distribution.    --Kyubey'))
        # Type check center and standard deviation.
        if (std_dev is None):
            raise InputError('Noise distribution is set to gaussian, there is '
                             'no standard deviation input.')
        else:
            # Standard deviation cannot be negative
            center = valid.validate_float_value(center)
            std_dev = valid.validate_float_value(std_dev, greater_than=0)
            noise_array = np.random.normal(center, std_dev, size=n_datapoints)

    # Noise array plus standard values.
    return input_array + noise_array
コード例 #20
0
def fit_dual_dimension_gaussian(points,
                                center_cutoff_factor=0.05,
                                height_cutoff_factor=0.42,
                                strip_width=0.2):
    """
    This function computes the values that describe a given 2D elliptical 
    gaussian.
    """
    try:
        n_datapoints = len(points[0])
    except:
        points = valid.validate_float_array(points)
        n_datapoints = len(points[0])

    # Type check, three dimensional points are expected.
    points = valid.validate_float_array(points, shape=(3, n_datapoints))
    center_cutoff_factor = valid.validate_float_value(center_cutoff_factor,
                                                      greater_than=0,
                                                      less_than=1)
    height_cutoff_factor = valid.validate_float_value(height_cutoff_factor,
                                                      greater_than=0,
                                                      less_than=1)
    strip_width = valid.validate_float_value(strip_width, greater_than=0)

    # Sort based off of z-values for convince.
    sort_index = np.argsort(points[2])
    points = points[:, sort_index]

    # Attempt to find the height of the gaussian. A weighted average of the
    # lowest z-points should be alright. The lower ceil(42%) is used just for
    # fun. The weight function is arbitrary, but used as it favors small values,
    # the points that might be considered at the bottom of the gaussian.
    height_cutoff = int(np.ceil(height_cutoff_factor * n_datapoints))
    fit_height = np.average(points[2, :height_cutoff],
                            weights=(1 / points[2, :height_cutoff]**2))

    # Do a translation to "zero-out" the datapoints along the z-axis
    points[2] -= fit_height

    # Attempt to find the center of the gaussian through weighted averages over
    # both axis. The cut off is such that the very low valued points do not
    # over power the average and the weights through attrition. The value of
    # ceil(5%) is arbitrary.
    center_cutoff = int(np.ceil(center_cutoff_factor * n_datapoints))
    x_center_fit = np.average(points[0, -center_cutoff:],
                              weights=points[2, -center_cutoff:]**2)
    y_center_fit = np.average(points[1, -center_cutoff:],
                              weights=points[2, -center_cutoff:]**2)
    fit_center = np.array([x_center_fit, y_center_fit], dtype=float)

    # Do a translation to center the datapoints along the xy-plane.
    points[0] -= x_center_fit
    points[1] -= y_center_fit

    # Determine the standard deviation. The normal fitting gaussian function
    # does not work as well because of the built in normalization factor.
    def subgauss(x_input, std_dev, amp, height):
        """
        This is a modified superset of gaussians.
        """
        # The centers should have already been detected and shifted. A priori
        # value
        center = 0
        # amp being the amplitude
        return ((amp * np.exp(-0.5 * ((x_input - center) / std_dev)**2)) +
                height)

    # Extract a strip of values along the x and y axes.
    x_valid_points = np.where(np.abs(points[1]) <= strip_width / 2.0)
    x_strip_points = points[:, x_valid_points[0]]

    y_valid_points = np.where(np.abs(points[0]) <= strip_width / 2.0)
    y_strip_points = points[:, y_valid_points[0]]

    x_gauss_ans = sp_opt.curve_fit(subgauss, x_strip_points[0],
                                   x_strip_points[2])
    y_gauss_ans = sp_opt.curve_fit(subgauss, y_strip_points[1],
                                   y_strip_points[2])

    # The only value desired is the standard deviation.
    x_std_dev = float(x_gauss_ans[0][0])
    y_std_dev = float(y_gauss_ans[0][0])
    fit_std_dev = np.array([x_std_dev, y_std_dev], dtype=float)

    # Package all of the obtained values. And return.
    return fit_center, fit_std_dev, fit_height
コード例 #21
0
def dual_dimensional_gauss_equation_rot(input_points, centers, std_devs,
                                        height, theta, dimensions):
    """
    This is the general gaussian equation for a rotatable gaussian for some 
    angle theta (in radians).
    """
    try:
        n_datapoints = len(input_points[0])
    except:
        input_points = valid.validate_float_array(input_points)
        n_datapoints = len(input_points[0])

    # Validate, dimensions must go first.
    dimensions = valid.validate_int_value(dimensions, greater_than=0)
    input_points = valid.validate_float_array(input_points,
                                              shape=(2, n_datapoints))
    centers = valid.validate_float_array(centers,
                                         shape=(dimensions, ),
                                         size=dimensions)
    std_devs = valid.validate_float_array(std_devs,
                                          shape=(dimensions, ),
                                          size=dimensions,
                                          deep_validate=True,
                                          greater_than=0)
    height = valid.validate_float_value(height)
    # Adapt for over/under rotation of theta.
    try:
        theta = valid.validate_float_value(theta,
                                           greater_than=0,
                                           less_than=2 * np.pi)
    except ValueError:
        # A loop is to be done. Have an insurance policy.
        loopbreak = 0
        while ((theta < 0) or (theta > 2 * np.pi)):
            if (theta < 0):
                theta += 2 * np.pi
            elif (theta > 0):
                theta = theta % (2 * np.pi)
            # Ensure that the loop does not get stuck in the event of
            # unpredicted behavior.
            loopbreak += 1
            if (loopbreak > 100):
                raise InputError('The value of theta cannot be '
                                 'nicely confined to 0 <= θ <= 2π '
                                 '    --Kyubey')

    # Following Wikipedia's parameter definitions.
    a = ((np.cos(theta)**2 / (2 * std_devs[0]**2)) + (np.sin(theta)**2 /
                                                      (2 * std_devs[1]**2)))
    b = (-(np.sin(2 * theta) / (4 * std_devs[0]**2)) + (np.sin(2 * theta) /
                                                        (4 * std_devs[1]**2)))
    c = ((np.sin(theta)**2 / (2 * std_devs[0]**2)) + (np.cos(theta)**2 /
                                                      (2 * std_devs[1]**2)))

    # Amplitude or normalization
    normalization_term = 1 / (2 * np.pi * std_devs[0] * std_devs[1])

    # General equation
    z_values = (normalization_term *
                np.exp(-(a * (input_points[0] - centers[0])**2 +
                         (2 * b * ((input_points[0] - centers[0]) *
                                   (input_points[1] - centers[1]))) +
                         (c * (input_points[1] - centers[1])**2))))

    # Return values.
    output_points = np.append(input_points, np.array([z_values]), axis=0)

    return z_values, output_points
コード例 #22
0
def line_integral_boundaries(view_line_point,
                             cloud_equation,
                             box_width,
                             view_line_deltas=(1, 0, 0),
                             n_guesses=100):
    """
    This function determines the points that intersect the sphere, starting
    with it entering and exit. It returns the ranges of points that would
    yield line integral boundaries that integrate within the cloud volume.

    By default, the cloud equation should be a function such that it returns a
    float, f(x,y,z), based on implicit shape making: f(x,y,z) = 0. If not, it
    should be at least a string that contains the python syntax expression of
    the shape for f(x,y,z) = 0, i.e., left-hand side of the equation only.
    """

    # Type check.
    view_line_point = valid.validate_float_array(view_line_point, shape=(3, ))
    # Check for both cases.
    try:
        cloud_function = valid.validate_function_call(cloud_equation,
                                                      n_parameters=3)
    except Exception:
        # Warn the user that sympy parsing is going to be used.
        # Try to use a sympy parsing. Assume a normal cartesian implicit
        # surface.
        variables = ('x', 'y', 'z')
        cloud_function = misc.user_equation_parse(cloud_equation, variables)
    box_width = valid.validate_float_value(box_width, greater_than=0)

    # Define the sightline parametric equations.
    def x_param(t):
        return view_line_deltas[0] * t + view_line_point[0]

    def y_param(t):
        return view_line_deltas[1] * t + view_line_point[1]

    def z_param(t):
        return view_line_deltas[2] * t + view_line_point[2]

    # Assume that the user's function accepts x,y,z in that order.
    def parameterized_cloud_equation(t):
        return cloud_function(x_param(t), y_param(t), z_param(t))

    # Find all of the roots of the parameterized function.
    initial_guesses = np.linspace(-box_width, box_width, n_guesses)
    eq_roots = sp_opt.fsolve(parameterized_cloud_equation,
                             initial_guesses,
                             xtol=1e-10)
    sort_eq_roots = np.sort(eq_roots)

    # Have only unique roots.
    unique_index = (np.abs(sort_eq_roots[1:] - sort_eq_roots[:-1])) > 1e-8
    neg_bound_roots = sort_eq_roots[:-1][unique_index]
    pos_bound_roots = sort_eq_roots[1:][unique_index]

    # There always exists an odd number of regions. The surface is closed and
    # has an even number of intersections by the sightline that passes in and
    # out of the surface as per topology. By default, the first and last groups
    # will not be within the cloud by the closed nature of the cloud. Assume
    # that the light goes from -x -> +x such that the yz plane is normal when
    # 'seen', thus the observer is near +x axis head.
    lower_bounds = neg_bound_roots[0::2]
    upper_bounds = pos_bound_roots[0::2]

    return lower_bounds, upper_bounds