<commit_before>"""All of the kinds of traces in UConnRCMPy"""

# System imports

# Third-party imports
import numpy as np
import cantera as ct
from scipy import signal as sig

# Local imports
from .constants import (one_atm_in_bar,
                        one_atm_in_torr,
                        one_bar_in_pa,
                        )


class VoltageTrace(object):
    """Voltage signal from a single experiment.

    Parameters
    ----------
    file_path : `pathlib.Path`
        `~pathlib.Path` object associated with the particular experiment

    Attributes
    ----------
    signal : `numpy.ndarray`
        2-D array containing the raw signal from the experimental
        text file. First column is the time, second column is the
        voltage.
    time : `numpy.ndarray`
        The time loaded from the signal trace
    frequency : `int`
        The sampling frequency of the pressure trace
    filtered_voltage : `numpy.ndarray`
        The voltage trace after filtering
    smoothed_voltage : `numpy.ndarray`
        The voltage trace after filtering and smoothing
    """
    def __init__(self, file_path):
        self.file_path = file_path
        self.signal = np.genfromtxt(str(self.file_path))

        self.time = self.signal[:, 0]
        self.frequency = np.rint(1/self.time[1])

        self.filtered_voltage = self.filtering(self.signal[:, 1])
        self.smoothed_voltage = self.smoothing(self.filtered_voltage)

    def __repr__(self):
        return 'VoltageTrace(file_path={self.file_path!r})'.format(self=self)

    def smoothing(self, data, span=21):
        """Smooth the input using a moving average.

        Parameters
        ----------
        data : `numpy.ndarray`
            The data that should be smoothed
        span : `int`, optional
            The width of the moving average. Should be an odd integer.
            The number of points included in the average on either side
            of the current point is given by ``(span-1)/2``.

        Returns
        -------
        `numpy.ndarray`
            A 1-D array of the same length as the input data.

        Notes
        -----
        This function effects the smoothing by convolving the input
        array with a uniform window array whose values are equal to
        ``1.0/span`` and whose length is equal to ``span``. The
        `~scipy.signal.fftconvolve` function from SciPy is used
        to do the convolution for speed. Since we desire an output
        array of the same length as the input, the first ``(span-1)/2``
        points will have improper values, so these are set equal to the
        value of the average at the point ``(span-1)/2``.
        """
        window = np.ones(span)/span
        output = sig.fftconvolve(data, window, mode='same')
        midpoint = int((span - 1)/2)
        output[:midpoint] = output[midpoint]
        return output

    def filtering(self, data, cutoff_hz=10000):
        """Filter the input using a low-pass filter.

        Parameters
        ----------
        data : `numpy.ndarray`
            The data that should be filtered
        cutoff_hz : `int`, optional
            The cutoff frequency for the filter, in Hz. The default
            value was chosen empirically for a particular set of data
            and may need to be adjusted.

        Returns
        -------
        `numpy.ndarray`
            1-D array of the same length as the input data

        Notes
        -----
        Creates a low-pass filter using the window construction funtion
        `~scipy.signal.firwin`. Applies the filter using the
        `~scipy.signal.fftconvolve` function from the same module
        for speed. Defaults to the `~scipy.signal.blackman` window
        for the filter.
        """
        nyquist_freq = self.frequency/2.0
        n_taps = 2**14
        low_pass_filter = sig.firwin(
            n_taps,
            cutoff_hz/nyquist_freq,
            window='blackman',
        )
        return sig.fftconvolve(data, low_pass_filter, mode='same')


class ExperimentalPressureTrace(object):
    """Pressure trace from a single experiment.

    Parameters
    ----------
    voltage_trace : `VoltageTrace`
        Instance of class containing the voltage trace of the
        experiment.
    initial_pressure_in_torr : `float`
        The initial pressure of the experiment, in units of Torr
    factor : `float`
        The factor set on the charge amplifier

    Attributes
    ----------
    pressure : `numpy.ndarray`
        The pressure trace computed from the smoothed and filtered
        voltage trace
    time : `numpy.ndarray`
        A 1-D array containting the time. Copied from
        `VoltageTrace.time`
    frequency : `int`
        Integer sampling frequency of the experiment. Copied from
        `VoltageTrace.frequency`
    p_EOC : `float`
        Pressure at the end of compression
    EOC_idx : `int`
        Integer index in the `pressure` and `time` arrays
        of the end of compression.
    is_reactive : `bool`
        Boolean if the pressure trace represents a reactive or
        or non-reactive experiment
    derivative : `numpy.ndarray`
        1-D array containing the raw derivative computed from the
        `pressure` trace.
    smoothed_derivative : `numpy.ndarray`
        1-D array containing the smoothed derivative computed from
        the `derivative`
    zeroed_time : `numpy.ndarray`
        1-D array containing the time, with the zero point set at
        the end of compression.
    """
    def __init__(self, voltage_trace, initial_pressure_in_torr, factor):
        initial_pressure_in_bar = initial_pressure_in_torr*one_atm_in_bar/one_atm_in_torr
        self.pressure = (voltage_trace.smoothed_voltage - voltage_trace.smoothed_voltage[0])
        self.pressure *= factor
        self.pressure += initial_pressure_in_bar

        self.time = voltage_trace.time
        self.frequency = voltage_trace.frequency

        self.p_EOC, self.EOC_idx, self.is_reactive = self.find_EOC()
        self.derivative = self.calculate_derivative(self.pressure, self.time)
        self.smoothed_derivative = voltage_trace.smoothing(self.derivative, span=151)
        self.zeroed_time = self.time - self.time[self.EOC_idx]

    def __repr__(self):
        return ('ExperimentalPressureTrace(p_EOC={self.p_EOC!r}, '
                'is_reactive={self.is_reactive!r})').format(self=self)

    def pressure_fit(self, comptime=0.08):
        """Fit a line to the pressure trace before EOC.

        Fit a line to the part of the pressure trace before compression
        starts.

        Parameters
        ----------<commit_msg>Adds file output methods for traces<commit_after>"""All of the kinds of traces in UConnRCMPy"""

# System imports

# Third-party imports
import numpy as np
import cantera as ct
from scipy import signal as sig

# Local imports
from .constants import (one_atm_in_bar,
                        one_atm_in_torr,
                        one_bar_in_pa,
                        )


class VoltageTrace(object):
    """Voltage signal from a single experiment.

    Parameters
    ----------
    file_path : `pathlib.Path`
        `~pathlib.Path` object associated with the particular experiment

    Attributes
    ----------
    signal : `numpy.ndarray`
        2-D array containing the raw signal from the experimental
        text file. First column is the time, second column is the
        voltage.
    time : `numpy.ndarray`
        The time loaded from the signal trace
    frequency : `int`
        The sampling frequency of the pressure trace
    filtered_voltage : `numpy.ndarray`
        The voltage trace after filtering
    smoothed_voltage : `numpy.ndarray`
        The voltage trace after filtering and smoothing
    """
    def __init__(self, file_path):
        self.file_path = file_path
        self.signal = np.genfromtxt(str(self.file_path))

        self.time = self.signal[:, 0]
        self.frequency = np.rint(1/self.time[1])

        self.filtered_voltage = self.filtering(self.signal[:, 1])
        self.smoothed_voltage = self.smoothing(self.filtered_voltage)

    def __repr__(self):
        return 'VoltageTrace(file_path={self.file_path!r})'.format(self=self)

    def savetxt(self, filename, **kwargs):
        """Save a text file output of the voltage trace.

        Save a text file with the time in the first column and the smoothed
        voltage in the second column. The keyword arguments are the same as
        `numpy.savetxt`.

        Parameters
        ----------
        filename : `str`
            Filename of the output file
        """
        np.savetxt(fname=filename, X=np.vstack(self.time, self.smoothed_voltage).T, **kwargs)

    def smoothing(self, data, span=21):
        """Smooth the input using a moving average.

        Parameters
        ----------
        data : `numpy.ndarray`
            The data that should be smoothed
        span : `int`, optional
            The width of the moving average. Should be an odd integer.
            The number of points included in the average on either side
            of the current point is given by ``(span-1)/2``.

        Returns
        -------
        `numpy.ndarray`
            A 1-D array of the same length as the input data.

        Notes
        -----
        This function effects the smoothing by convolving the input
        array with a uniform window array whose values are equal to
        ``1.0/span`` and whose length is equal to ``span``. The
        `~scipy.signal.fftconvolve` function from SciPy is used
        to do the convolution for speed. Since we desire an output
        array of the same length as the input, the first ``(span-1)/2``
        points will have improper values, so these are set equal to the
        value of the average at the point ``(span-1)/2``.
        """
        window = np.ones(span)/span
        output = sig.fftconvolve(data, window, mode='same')
        midpoint = int((span - 1)/2)
        output[:midpoint] = output[midpoint]
        return output

    def filtering(self, data, cutoff_hz=10000):
        """Filter the input using a low-pass filter.

        Parameters
        ----------
        data : `numpy.ndarray`
            The data that should be filtered
        cutoff_hz : `int`, optional
            The cutoff frequency for the filter, in Hz. The default
            value was chosen empirically for a particular set of data
            and may need to be adjusted.

        Returns
        -------
        `numpy.ndarray`
            1-D array of the same length as the input data

        Notes
        -----
        Creates a low-pass filter using the window construction funtion
        `~scipy.signal.firwin`. Applies the filter using the
        `~scipy.signal.fftconvolve` function from the same module
        for speed. Defaults to the `~scipy.signal.blackman` window
        for the filter.
        """
        nyquist_freq = self.frequency/2.0
        n_taps = 2**14
        low_pass_filter = sig.firwin(
            n_taps,
            cutoff_hz/nyquist_freq,
            window='blackman',
        )
        return sig.fftconvolve(data, low_pass_filter, mode='same')


class ExperimentalPressureTrace(object):
    """Pressure trace from a single experiment.

    Parameters
    ----------
    voltage_trace : `VoltageTrace`
        Instance of class containing the voltage trace of the
        experiment.
    initial_pressure_in_torr : `float`
        The initial pressure of the experiment, in units of Torr
    factor : `float`
        The factor set on the charge amplifier

    Attributes
    ----------
    pressure : `numpy.ndarray`
        The pressure trace computed from the smoothed and filtered
        voltage trace
    time : `numpy.ndarray`
        A 1-D array containting the time. Copied from
        `VoltageTrace.time`
    frequency : `int`
        Integer sampling frequency of the experiment. Copied from
        `VoltageTrace.frequency`
    p_EOC : `float`
        Pressure at the end of compression
    EOC_idx : `int`
        Integer index in the `pressure` and `time` arrays
        of the end of compression.
    is_reactive : `bool`
        Boolean if the pressure trace represents a reactive or
        or non-reactive experiment
    derivative : `numpy.ndarray`
        1-D array containing the raw derivative computed from the
        `pressure` trace.
    smoothed_derivative : `numpy.ndarray`
        1-D array containing the smoothed derivative computed from
        the `derivative`
    zeroed_time : `numpy.ndarray`
        1-D array containing the time, with the zero point set at
        the end of compression.
    """
    def __init__(self, voltage_trace, initial_pressure_in_torr, factor):
        initial_pressure_in_bar = initial_pressure_in_torr*one_atm_in_bar/one_atm_in_torr
        self.pressure = (voltage_trace.smoothed_voltage - voltage_trace.smoothed_voltage[0])
        self.pressure *= factor
        self.pressure += initial_pressure_in_bar

        self.time = voltage_trace.time
        self.frequency = voltage_trace.frequency

        self.p_EOC, self.EOC_idx, self.is_reactive = self.find_EOC()
        self.derivative = self.calculate_derivative(self.pressure, self.time)
        self.smoothed_derivative = voltage_trace.smoothing(self.derivative, span=151)
        self.zeroed_time = self.time - self.time[self.EOC_idx]

    def __repr__(self):
        return ('ExperimentalPressureTrace(p_EOC={self.p_EOC!r}, '
                'is_reactive={self.is_reactive!r})').format(self=self)

    def savetxt(self, filename, **kwargs):
        """Save a text file output of the pressure trace.

        Save a text file with the time in the first column and the smoothed
        pressure in the second column. The keyword arguments are the same as
        `numpy.savetxt`.

        Parameters
        ----------
        filename : `str`
            Filename of the output file
        """
        np.savetxt(fname=filename, X=np.vstack(self.time, self.pressure).T, **kwargs)

    def pressure_fit(self, comptime=0.08):
        """Fit a line to the pressure trace before EOC.

        Fit a line to the part of the pressure trace before compression
        starts.

        Parameters
        ----------
{'fraction_non_alphanumeric': 0.08626242823134014, 'fraction_numerical': 0.005601456378658451, 'mean_word_length': 2.1460352422907487, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '195196', 'n_tokens_mistral': 4123, 'n_tokens_neox': 3888, 'n_words': 1335}