Example #1
0
def newMaskData(projData: ProjectData, sampleFreq: float) -> MaskData:
    """Get a mask data object that can then be passed onto calculateMask

    Parameters
    ----------
    projData : ProjectData
        A ProjectData instance
    sampleFreq : float
        The sampling frequency to mask
    
    Returns
    -------
    MaskData
        A mask data object with parameters set
    """

    decParams = getDecimationParameters(sampleFreq, projData.config)
    decParams.printInfo()
    return MaskData(decParams.sampleFreq, decParams.numLevels,
                    decParams.evalFreqPerLevel)
def processSite(projData: ProjectData, site: str,
                sampleFreq: Union[int, float], **kwargs):
    """Process a single sampling frequency for a site

    The site passed is assumed to be the output site (the output channels will come from this site). If channels from a different site are desired to be used as the input channels, this can be done by specifying the optional inputsite argument.

    .. todo:: Give a few different examples here

    Parameters
    ----------
    projData : ProjectData
        The project data instance for the project
    site : str
        Site to process 
    sampleFreq : float, int
        Sample frequency to process
    specdir : str, optional
        The spectra directories to use
    inchans : List[str], optional
        Channels to use as the input of the linear system
    inputsite : str, optional
        Site from which to take the input channels. The default is to use input and output channels from the same site
    outchans : List[str], optional
        Channels to use as the output of the linear system
    remotesite : str, optional
        The site to use as the remote site
    remotechans : List[str], optional
        Channels to use from the remote reference site
    crosschannels : List[str], optional
        List of channels to use for cross powers
    masks : Dict, optional
        Masks dictionary for passing mask data. The key should be a site name and the value should either be a string for a single mask or a list of multiple masks.
    datetimes : List, optional
        List of datetime constraints, each one as a dictionary. For example [{"type": "datetime", "start": 2018-08-08 00:00:00, "end": 2018-08-08 16:00:00, "levels": [0,1]}]. Note that levels is optional.
    postpend : str, optional
        String to postpend to the transfer function output
    """

    options = {}
    options["specdir"] = projData.config.configParams["Spectra"]["specdir"]
    options["inchans"] = ["Hx", "Hy"]
    options["inputsite"] = ""
    options["outchans"] = ["Ex", "Ey"]
    options["remotesite"] = ""
    options["remotechans"] = options["inchans"]
    options["crosschannels"] = []
    options["masks"] = {}
    options["datetimes"] = []
    options["postpend"] = ""
    options = parseKeywords(options, kwargs)
    if options["inputsite"] == "":
        options["inputsite"] = site

    projectText("Processing site {}, sampling frequency {}".format(
        site, sampleFreq))
    siteData = projData.getSiteData(site)

    # define decimation parameters
    decParams = getDecimationParameters(sampleFreq, projData.config)
    decParams.printInfo()
    winParams = getWindowParameters(decParams, projData.config)
    # window selector
    winSelector = getWindowSelector(projData, decParams, winParams)

    # if two sites are duplicated (e.g. input site and output site), winSelector only uses distinct sites. Hence using site and inputSite is no problem even if they are the same
    processSites = []
    if options["remotesite"]:
        processSites = [site, options["inputsite"], options["remotesite"]]
        winSelector.setSites(processSites)
    else:
        # if no remote site, then single site processing
        processSites = [site, options["inputsite"]]
        winSelector.setSites(processSites)

    # add window masks
    if len(list(options["masks"].keys())) > 0:
        for maskSite in options["masks"]:
            if maskSite not in processSites:
                # there is a site in the masks dictionary which is of no interest
                continue
            if isinstance(options["masks"][maskSite], str):
                # a single mask
                winSelector.addWindowMask(maskSite, options["masks"][maskSite])
                continue
            if all(
                    isinstance(item, str)
                    for item in options["masks"][maskSite]):
                # list of masks for the site
                for mask in options["masks"][maskSite]:
                    winSelector.addWindowMask(maskSite, mask)

    # add datetime constraints
    for dC in options["datetimes"]:
        levels = None
        if "levels" in dC:
            levels = dC["levels"]

        if dC["type"] == "datetime":
            winSelector.addDatetimeConstraint(dC["start"], dC["stop"], levels)
        if dC["type"] == "time":
            winSelector.addTimeConstraint(dC["start"], dC["stop"], levels)
        if dC["type"] == "date":
            winSelector.addDateConstraint(dC["date"], levels)

    # calculate the shared windows and print info
    winSelector.calcSharedWindows()
    winSelector.printInfo()
    winSelector.printDatetimeConstraints()
    winSelector.printWindowMasks()
    winSelector.printSharedWindows()
    winSelector.printWindowsForFrequency()

    # now have the windows, pass the winSelector to processors
    outPath = siteData.transFuncPath
    if options["remotesite"]:
        projectText(
            "Remote reference processing with sites: in = {}, out = {}, reference = {}"
            .format(options["inputsite"], site, options["remotesite"]))
        processor = getRemoteReferenceProcessor(winSelector, outPath,
                                                projData.config)
        processor.setRemote(options["remotesite"], options["remotechans"])
    else:
        projectText(
            "Single site processing with sites: in = {}, out = {}".format(
                options["inputsite"], site))
        processor = getSingleSiteProcessor(winSelector, outPath,
                                           projData.config)

    # add the input and output site
    processor.setInput(options["inputsite"], options["inchans"])
    processor.setOutput(site, options["outchans"])
    if len(options["crosschannels"]) > 0:
        processor.crossChannels = options["crosschannels"]
    processor.postpend = options["postpend"]
    processor.printInfo()
    processor.process()
Example #3
0
def calculateRemoteStatistics(projData: ProjectData, remoteSite: str,
                              **kwargs):
    """Calculate statistics involving a remote reference site

    
    Parameters
    ----------
    projData : ProjectData
        A project data instance
    remoteSite : str
        The name of the site to use as the remote site
    sites : List[str], optional
        A list of sites to calculate statistics for
    sampleFreqs : List[float], optional
        List of sampling frequencies for which to calculate statistics
    chans : List[str], optional
        List of data channels to use
    specdir : str, optional
        The spectra directory for which to calculate statistics
    remotestats : List[str], optional
        The statistics to calculate out. Acceptable statistics are: "RR_coherence", "RR_coherenceEqn", "RR_absvalEqn", "RR_transferFunction", "RR_resPhase". Configuration file values are used by default.
    """

    options = {}
    options["sites"] = projData.getSites()
    options["sampleFreqs"] = projData.getSampleFreqs()
    options["chans"] = []
    options["specdir"] = projData.config.configParams["Spectra"]["specdir"]
    options["remotestats"] = projData.config.configParams["Statistics"][
        "remotestats"]
    options = parseKeywords(options, kwargs)

    projectText(
        "Calculating stats: {} for sites: {} with remote site {}".format(
            listToString(options["remotestats"]),
            listToString(options["sites"]),
            remoteSite,
        ))

    # create the statistic calculator and IO object
    statCalculator = StatisticCalculator()
    statIO = StatisticIO()

    # loop over sites
    for site in options["sites"]:
        siteData = projData.getSiteData(site)
        measurements = siteData.getMeasurements()

        for meas in measurements:
            sampleFreq = siteData.getMeasurementSampleFreq(meas)
            if sampleFreq not in options["sampleFreqs"]:
                # don't need to calculate statistics for this sampling frequency
                continue

            projectText(
                "Calculating stats for site {}, measurement {} with reference {}"
                .format(site, meas, remoteSite))

            # decimation and window parameters
            decParams = getDecimationParameters(sampleFreq, projData.config)
            decParams.printInfo()
            numLevels = decParams.numLevels
            winParams = getWindowParameters(decParams, projData.config)

            # create the window selector and find the shared windows
            winSelector = getWindowSelector(projData, decParams, winParams)
            winSelector.setSites([site, remoteSite])
            # calc shared windows between site and remote
            winSelector.calcSharedWindows()
            # create the spectrum reader
            specReader = SpectrumReader(
                os.path.join(siteData.getMeasurementSpecPath(meas),
                             options["specdir"]))

            # loop through decimation levels
            for iDec in range(0, numLevels):
                # open the spectra file for the current decimation level
                check = specReader.openBinaryForReading("spectra", iDec)
                if not check:
                    # probably because this decimation level not calculated
                    continue
                specReader.printInfo()

                # get a set of the shared windows at this decimation level
                # these are the global indices
                sharedWindows = winSelector.getSharedWindowsLevel(iDec)

                # get other information regarding only this spectra file
                refTime = specReader.getReferenceTime()
                winSize = specReader.getWindowSize()
                winOlap = specReader.getWindowOverlap()
                numWindows = specReader.getNumWindows()
                evalFreq = decParams.getEvalFrequenciesForLevel(iDec)
                sampleFreqDec = specReader.getSampleFreq()
                globalOffset = specReader.getGlobalOffset()
                fArray = specReader.getFrequencyArray()

                # now want to find the size of the intersection between the windows in this file and the shared windows
                sharedWindowsMeas = sharedWindows.intersection(
                    set(np.arange(globalOffset, globalOffset + numWindows)))
                sharedWindowsMeas = sorted(list(sharedWindowsMeas))
                numSharedWindows = len(sharedWindowsMeas)

                statHandlers = {}
                # create the statistic handlers
                for stat in options["remotestats"]:
                    statElements = getStatElements(stat)
                    statHandlers[stat] = StatisticData(stat, refTime,
                                                       sampleFreqDec, winSize,
                                                       winOlap)
                    # remember, this is with the remote reference, so the number of windows is number of shared windows
                    statHandlers[stat].setStatParams(numSharedWindows,
                                                     statElements, evalFreq)
                    statHandlers[stat].comments = specReader.getComments()
                    statHandlers[stat].addComment(
                        projData.config.getConfigComment())
                    statHandlers[stat].addComment(
                        "Calculating remote statistic: {}".format(stat))
                    statHandlers[stat].addComment(
                        "Statistic components: {}".format(
                            listToString(statElements)))

                # loop over the shared windows between the remote station and local station
                for iW, globalWindow in enumerate(sharedWindowsMeas):
                    # get data and set in the statCalculator
                    winData = specReader.readBinaryWindowGlobal(globalWindow)
                    statCalculator.setSpectra(fArray, winData, evalFreq)
                    # for the remote site, use the reader in win selector
                    remoteSF, remoteReader = winSelector.getSpecReaderForWindow(
                        remoteSite, iDec, globalWindow)
                    winDataRR = remoteReader.readBinaryWindowGlobal(
                        globalWindow)
                    statCalculator.addRemoteSpec(winDataRR)

                    for sH in statHandlers:
                        data = statCalculator.getDataForStatName(sH)
                        statHandlers[sH].addStat(iW, globalWindow, data)

                # save statistic
                for sH in statHandlers:
                    statIO.setDatapath(
                        os.path.join(siteData.getMeasurementStatPath(meas),
                                     options["specdir"]))
                    statIO.write(statHandlers[sH], iDec)
Example #4
0
def calculateStatistics(projData: ProjectData, **kwargs):
    """Calculate statistics for sites
    
    Parameters
    ----------
    projData : ProjectData
        A project data instance
    sites : List[str], optional
        A list of sites to calculate statistics for
    sampleFreqs : List[float], optional
        List of sampling frequencies for which to calculate statistics
    chans : List[str], optional
        List of data channels to use
    specdir : str, optional
        The spectra directory for which to calculate statistics
    stats : List[str], optional
        The statistics to calculate out. Acceptable values are: "absvalEqn" "coherence", "psd", "poldir", "transFunc", "resPhase", "partialcoh". Configuration file values are used by default.
    """

    options = {}
    options["sites"] = projData.getSites()
    options["sampleFreqs"] = projData.getSampleFreqs()
    options["chans"] = []
    options["specdir"] = projData.config.configParams["Spectra"]["specdir"]
    options["stats"] = projData.config.configParams["Statistics"]["stats"]
    options = parseKeywords(options, kwargs)

    projectText("Calculating stats: {} for sites: {}".format(
        listToString(options["stats"]), listToString(options["sites"])))

    # create the statistic calculator and IO object
    statCalculator = StatisticCalculator()
    statIO = StatisticIO()

    # loop through sites and calculate statistics
    for site in options["sites"]:
        siteData = projData.getSiteData(site)
        measurements = siteData.getMeasurements()

        for meas in measurements:
            sampleFreq = siteData.getMeasurementSampleFreq(meas)
            if sampleFreq not in options["sampleFreqs"]:
                # don't need to calculate statistics for this sampling frequency
                continue

            projectText("Calculating stats for site {}, measurement {}".format(
                site, meas))

            # decimation parameters
            decParams = getDecimationParameters(sampleFreq, projData.config)
            decParams.printInfo()
            numLevels = decParams.numLevels

            # create the spectrum reader
            specReader = SpectrumReader(
                os.path.join(siteData.getMeasurementSpecPath(meas),
                             options["specdir"]))

            # loop through decimation levels
            for iDec in range(0, numLevels):
                # open the spectra file for the current decimation level
                check = specReader.openBinaryForReading("spectra", iDec)
                if not check:
                    # probably because this decimation level not calculated
                    continue
                specReader.printInfo()

                # get windows
                refTime = specReader.getReferenceTime()
                winSize = specReader.getWindowSize()
                winOlap = specReader.getWindowOverlap()
                numWindows = specReader.getNumWindows()
                evalFreq = decParams.getEvalFrequenciesForLevel(iDec)
                sampleFreqDec = specReader.getSampleFreq()
                globalOffset = specReader.getGlobalOffset()
                fArray = specReader.getFrequencyArray()

                statHandlers = {}
                # create the statistic handlers
                for stat in options["stats"]:
                    statElements = getStatElements(stat)
                    statHandlers[stat] = StatisticData(stat, refTime,
                                                       sampleFreqDec, winSize,
                                                       winOlap)
                    statHandlers[stat].setStatParams(numWindows, statElements,
                                                     evalFreq)
                    statHandlers[stat].comments = specReader.getComments()
                    statHandlers[stat].addComment(
                        projData.config.getConfigComment())
                    statHandlers[stat].addComment(
                        "Calculating statistic: {}".format(stat))
                    statHandlers[stat].addComment(
                        "Statistic components: {}".format(
                            listToString(statElements)))

                # loop over windows and calculate the relevant statistics
                for iW in range(0, numWindows):
                    # get data
                    winData = specReader.readBinaryWindowLocal(iW)
                    globalIndex = iW + globalOffset
                    # give the statistic calculator the spectra
                    statCalculator.setSpectra(fArray, winData, evalFreq)
                    # get the desired statistics
                    for sH in statHandlers:
                        data = statCalculator.getDataForStatName(sH)
                        statHandlers[sH].addStat(iW, globalIndex, data)

                # save statistic
                for sH in statHandlers:
                    statIO.setDatapath(
                        os.path.join(siteData.getMeasurementStatPath(meas),
                                     options["specdir"]))
                    statIO.write(statHandlers[sH], iDec)
Example #5
0
def calculateMask(projData: ProjectData, maskData: MaskData, **kwargs):
    """Calculate masks sites

    Parameters
    ----------
    projData : projectData
        A project instance
    maskData : MaskData
        A mask data instance
    sites : List[str], optional
        A list of sites to calculate masks for
    specdir : str, optional
        The spectra directory for which to calculate statistics
    """

    options = {}
    options["sites"] = projData.getSites()
    options["specdir"] = projData.config.configParams["Spectra"]["specdir"]
    options = parseKeywords(options, kwargs)

    # create a maskCalculator object
    maskCalc = MaskCalculator(projData, maskData, specdir=options["specdir"])
    maskIO = MaskIO()
    sampleFreq = maskData.sampleFreq

    # loop over sites
    for site in options["sites"]:
        # see if there is a sample freq
        siteData = projData.getSiteData(site)
        siteSampleFreqs = siteData.getSampleFreqs()
        if sampleFreq not in siteSampleFreqs:
            continue

        # decimation and window parameters
        decParams = getDecimationParameters(sampleFreq, projData.config)
        decParams.printInfo()
        winParams = getWindowParameters(decParams, projData.config)

        # clear previous windows from maskCalc
        maskCalc.clearMaskWindows()
        # calculate masked windows
        maskCalc.applyConstraints(site)
        maskCalc.maskData.printInfo()

        # write maskIO file
        maskIO.datapath = os.path.join(
            siteData.getSpecdirMaskPath(options["specdir"]))
        maskIO.write(maskCalc.maskData)

        # test with the window selector
        winSelector = WindowSelector(projData,
                                     sampleFreq,
                                     decParams,
                                     winParams,
                                     specdir=options["specdir"])
        winSelector.setSites([site])
        winSelector.addWindowMask(site, maskData.maskName)
        winSelector.calcSharedWindows()
        winSelector.printInfo()
        winSelector.printDatetimeConstraints()
        winSelector.printWindowMasks()
        winSelector.printSharedWindows()
        winSelector.printWindowsForFrequency()
Example #6
0
import os
from resistics.project.projectIO import loadProject

# load project and configuration file
projectPath = os.path.join("tutorialProject")
projData = loadProject(projectPath, configFile="tutorialConfig.ini")

# get decimation parameters
from resistics.utilities.utilsProject import getDecimationParameters

decimationParameters = getDecimationParameters(4096, projData.config)
decimationParameters.printInfo()

# get the window parameters
from resistics.utilities.utilsProject import getWindowParameters

windowParameters = getWindowParameters(decimationParameters, projData.config)
windowParameters.printInfo()

from resistics.utilities.utilsProject import getWindowSelector

decimationParameters = getDecimationParameters(128, projData.config)
windowParameters = getWindowParameters(decimationParameters, projData.config)
selector = getWindowSelector(projData, decimationParameters, windowParameters)
selector.printInfo()

# add a site and print the information to the terminal
selector.setSites(["site1"])
selector.printInfo()

# calculate shared windows
Example #7
0
def calculateSpectra(projData: ProjectData, **kwargs) -> None:
    """Calculate spectra for the project time data

    The philosophy is that spectra are calculated out for all data and later limited using statistics and time constraints

    Parameters
    ----------
    projData : ProjectData
        A project data object
    sites : str, List[str], optional
        Either a single site or a list of sites
    sampleFreqs : int, float, List[float], optional
        The frequencies in Hz for which to calculate the spectra. Either a single frequency or a list of them.
    chans : List[str], optional
        The channels for which to calculate out the spectra
    polreverse :  Dict[str, bool]
        Keys are channels and values are boolean flags for reversing
    scale : Dict[str, float]
        Keys are channels and values are floats to multiply the channel data by
    calibrate : bool, optional
        Flag whether to calibrate the data or not
    notch : List[float], optional
        List of frequencies to notch
    filter : Dict, optional
        Filter parameters
    specdir : str, optional
        The spectra directory to save the spectra data in
    """

    # default options
    options = {}
    options["sites"] = projData.getSites()
    options["sampleFreqs"]: List[float] = projData.getSampleFreqs()
    options["chans"]: List[str] = []
    options["polreverse"]: Union[bool, Dict[str, bool]] = False
    options["scale"]: Union[bool, Dict[str, float]] = False       
    options["calibrate"]: bool = True
    options["notch"]: List[float] = []
    options["filter"]: Dict = {}
    options["specdir"]: str = projData.config.configParams["Spectra"]["specdir"]
    options = parseKeywords(options, kwargs)

    # prepare calibrator
    cal = getCalibrator(projData.calPath, projData.config)
    if options["calibrate"]:
        cal.printInfo()

    datetimeRef = projData.refTime
    for site in options["sites"]:
        siteData = projData.getSiteData(site)
        siteData.printInfo()

        # calculate spectra for each frequency
        for sampleFreq in options["sampleFreqs"]:
            measurements = siteData.getMeasurements(sampleFreq)
            projectText(
                "Site {} has {:d} measurement(s) at sampling frequency {:.2f}".format(
                    site, len(measurements), sampleFreq
                )
            )
            if len(measurements) == 0:
                continue  # no data files at this sample rate

            for meas in measurements:
                projectText(
                    "Calculating spectra for site {} and measurement {}".format(
                        site, meas
                    )
                )
                # get measurement start and end times - this is the time of the first and last sample
                reader = siteData.getMeasurement(meas)
                startTime = siteData.getMeasurementStart(meas)
                stopTime = siteData.getMeasurementEnd(meas)
                dataChans = (
                    options["chans"]
                    if len(options["chans"]) > 0
                    else reader.getChannels()
                )
                timeData = reader.getPhysicalData(startTime, stopTime, chans=dataChans)
                timeData.addComment(breakComment())
                timeData.addComment("Calculating project spectra")
                timeData.addComment(projData.config.getConfigComment())

                # apply various options
                applyPolarisationReversalOptions(options, timeData)
                applyScaleOptions(options, timeData)
                applyCalibrationOptions(options, cal, timeData, reader)
                applyFilterOptions(options, timeData)
                applyNotchOptions(options, timeData)

                # define decimation and window parameters
                decParams = getDecimationParameters(sampleFreq, projData.config)
                decParams.printInfo()
                numLevels = decParams.numLevels
                winParams = getWindowParameters(decParams, projData.config)
                dec = Decimator(timeData, decParams)
                timeData.addComment(
                    "Decimating with {} levels and {} frequencies per level".format(
                        numLevels, decParams.freqPerLevel
                    )
                )

                # loop through decimation levels
                for iDec in range(0, numLevels):
                    # get the data for the current level
                    check = dec.incrementLevel()
                    if not check:
                        break  # not enough data
                    timeData = dec.timeData

                    # create the windower and give it window parameters for current level
                    sampleFreqDec = dec.sampleFreq
                    win = Windower(
                        datetimeRef,
                        timeData,
                        winParams.getWindowSize(iDec),
                        winParams.getOverlap(iDec),
                    )
                    if win.numWindows < 2:
                        break  # do no more decimation

                    # add some comments
                    timeData.addComment(
                        "Evaluation frequencies for this level {}".format(
                            listToString(decParams.getEvalFrequenciesForLevel(iDec))
                        )
                    )
                    timeData.addComment(
                        "Windowing with window size {} samples and overlap {} samples".format(
                            winParams.getWindowSize(iDec), winParams.getOverlap(iDec)
                        )
                    )

                    # create the spectrum calculator and statistics calculators
                    specCalc = SpectrumCalculator(
                        sampleFreqDec, winParams.getWindowSize(iDec)
                    )
                    # get ready a file to save the spectra
                    specPath = os.path.join(
                        siteData.getMeasurementSpecPath(meas), options["specdir"]
                    )
                    specWrite = SpectrumWriter(specPath, datetimeRef)
                    specWrite.openBinaryForWriting(
                        "spectra",
                        iDec,
                        sampleFreqDec,
                        winParams.getWindowSize(iDec),
                        winParams.getOverlap(iDec),
                        win.winOffset,
                        win.numWindows,
                        dataChans,
                    )

                    # loop though windows, calculate spectra and save
                    for iW in range(0, win.numWindows):
                        # get the window data
                        winData = win.getData(iW)
                        # calculate spectra
                        specData = specCalc.calcFourierCoeff(winData)
                        # write out spectra
                        specWrite.writeBinary(specData)

                    # close spectra file
                    specWrite.writeCommentsFile(timeData.getComments())
                    specWrite.closeFile()