예제 #1
0
def run(nchan, lwidth, inten):
    """ Method to generate spectra and inject Gaussians

        Parameters
        ----------
        nchan : int
            Number of channels in the generated spectrum

        lwidth : float
            Width of the generated Gaussians in km/s

        inten : float
            The nominal peak intensity of the Gaussians
    """
    # set up the dict to collect the results, key is the number of Gaussians to inject
    pats = {5: None, 10: None, 15:None, 20:None, 25:None, 30:None, 40:None, 50:None, 60:None, 70:None, 80:None, 90:None, 100:None}
    nl = pats.keys()
    nl.sort()
    # for each of the number of Gaussians
    for nlines in nl:
        print "    ",nlines
        # generate frequency axis
        rms = 1.0
        freq = np.arange(nchan, dtype=np.float64)
        center = int(nchan/2)
        for i in range(nchan):
            freq[i] = 100.0 + (float((i - nchan/2)) * 0.0001)
        # generate spectral and channel axes
        spec = np.zeros(nchan)
        chans = np.arange(nchan)
        # generate noise
        spec += np.random.normal(0.0, rms, nchan)
        # inject Gaussians
        for i in range(nlines):
            # randomly determine the peak position in channel space
            peak = int(random.random() * nchan)
            spec += utils.gaussian1D(freq, inten, freq[peak] + (random.random()/20), utils.veltofreq(lwidth, freq[peak]))
        # convert to Spectrum object
        spectrum = Spectrum(spec, freq, chans)
        # find the segments
        sfinder = SegmentFinder.SegmentFinder(spectrum=spectrum.spec(),
                                              freq=spectrum.freq(),
                                              method="ADMIT",
                                              minchan=3,
                                              maxgap=3,
                                              numsigma=4.0,
                                              iterate=True, nomean=True)

        seg, cut, noi, mean = sfinder.find()
        spectrum.set_noise(noi)
        # find the peaks
        args = {"spec"      : spectrum.spec(),
                "y"         : spectrum.freq(),
                "min_width" : 3}
        args["thresh"] = float(spectrum.noise() * 4.0)
        pks = getpeaks("PeakFinder", args, spectrum.spec(), seg, iterate=True)
        # find any patterns
        pats[nlines] = findpatterns(spectrum, pks, seg)
    return pats
예제 #2
0
    def convert(self, chan=None, freq=None, velocity=None, spec=None, file=None, separator=None, 
                restfreq=None, vlsr=None):
        """ Method to convert input data (either files or arrays) into a CubeSpectrum_BDP. If files
            are used then then the columns containing the frequency and the intensity must be given
            (channel numbers are optional). Any number of files can be given, but all spectra must
            have the same length as they are assumed to come from the same data source. Blank lines
            and lines starting with a comment '#' will be skipped, additionally any line with too
            few columns will be skipped. If arrays are used an input then both the frequency and
            intensity must be specified (the channel numbers are optional). Both lists and numpy
            arrays are accepted as inputs. Multidimmensional arrays are supported with the following
            parameters:

            + A single frequency list can be given to cover all input spectra, otherwise the shape
              of the frequency array must match that of the spectra
            + A single channel list can be given to cover all input spectra, otherwise the shape
              of the channel array must match that of the spectra
            + All spectra must have the same length

            If a channel array is not specified then one will be constructed with the following
            parameters:

            + The channel numbers will start at 0 (casa convention)
            + The first entry in the spectrum will be considered the first channel, regardless of
              whether the frequency array increases or decreases.

            Additionally, if there is velocity axis, but no frequency axis, a frequency axis can
            be constructed by specifying a rest frequency (restfreq), and vlsr.

            The convert method will return a single CubeSpectrum_BDP instance holding all input spectra
            along with an image of each.

            Parameters
            ----------
            chan : array or int
                An array holding the channel numbers for the data, multidimmensional arrays are
                supported. If an integer is specified then it is the number of the column
                in the file which contains the channel numbers, column numbers are 1 based.
                Default: None

            freq : array
                An array holding the frequencies for the data, multidimmensional arrays are
                supported. If an integer is specified then it is the number of the column
                in the file which contains the frequencies, column numbers are 1 based.
                Default: None

            velocity : array
                An array holding the velocity for the data, multidimmensional arrays are
                supported. If an integer is specified then it is the number of the column
                in the file which contains the velcoties, column numbers are 1 based. If this
                parameter is specified then restfreq and vlsr must also be specified.
                Default: None

            spec : array
                An array holding the intesities of the data, multidimmensional arrays are supported.
                If an integer is specified then it is the number of the column in the file which
                contains the intensities, column numbers are 1 based.
                Default: None

            file : list or str
                A single file name or a list of file names to be read in for spectra.
                Default: None

            separator : str
                The column separator for reading in the data files.
                Default: None (any whitespace)

            restfreq : float
                The rest frequency to use to convert the spectra from velocity to frequency units.
                The rest frequency is in GHz.
                Default: None (no conversion done)

            vlsr : float
                The reference velocity for converting a velocity axis to frequency. The units are
                km/s. If this is not set then it is assumed that the vlsr is 0.0.
                Default: None

            Returns
            -------
            CubeSpectrum_BDP instance containing all of the inpur spectra.

        """
        self.restfreq = restfreq
        self.vlsr = vlsr

        # if a string was given as the file name then turn it into a list so it can be iterated over
        if isinstance(file, str):
            self.file = [file]
        else:
            self.file = file
        # do some error checking
        if isinstance(chan, np.ndarray) or isinstance(chan, list):
            if isinstance(chan, list):
                self.chan = np.array(chan)
            else:
                self.chan = copy.deepcopy(chan)
            self.chancol = -1
        elif isinstance(chan, int):
            self.chancol = chan
            self.chan = None
        else:
            self.chancol = -1
            self.chan = None
        if isinstance(freq, np.ndarray) or isinstance(freq, list):
            if isinstance(freq, list):
                self.freq = np.array(freq)
            else:
                self.freq = copy.deepcopy(freq)
            self.freqcol = -1
        elif isinstance(freq, int):
            self.freqcol = freq
            self.freq = None
        else:
            self.freqcol = -1
            self.freq = None
        if isinstance(velocity, np.ndarray) or isinstance(velocity, list):
            if isinstance(velocity, list):
                self.freq = np.array(velocity, dtype=np.float)
            else:
                self.freq = velocity.astype(np.float)
            for i, frq in enumerate(self.freq):
                self.freq[i] = self.restfreq + utils.veltofreq(frq - self.vlsr, self.restfreq)
            self.freqcol = -1
        elif isinstance(velocity, int):
            self.velcol = velocity
            self.velocity = None
        else:
            self.velcol = -1
            self.velocity = None
        if isinstance(spec, np.ndarray) or isinstance(spec, list):
            if isinstance(spec, list):
                self.spec = np.array(spec)
            else:
                self.spec = copy.deepcopy(spec)
            self.speccol = -1
        elif isinstance(spec, int):
            self.speccol = spec
            self.spec = None
        else:
            self.speccol = -1
            self.spec = None
        if isinstance(separator, str):
            self.separator = separator
        spectra = []
        # read in the data from any files
        if self.file:
            for fl in self.file:
                spectra.append(self.getfile(fl))
        else:
            # convert the input arrays
            singlefreq = False
            singlechan = False
            havechan = False
            # make sure they have the same shape or that the frequency array is 1D
            if self.spec.shape != self.freq.shape:
                if len(self.spec.shape) == 1 and len(self.freq.shape) != 1:
                    raise Exception("Frequency axis and spectral axis do not have the same shape.")
                else:
                    singlefreq = True
            # make sure they have the same shape or that the channel array is 1D
            if self.chan:
                havechan = True
                if self.spec.shape != self.chan.shape:
                    if len(spec.shape) == 1 and len(self.chan.shape) != 1:
                        raise Exception("Channel axis and spectral axis do not have the same shape.")
                    else:
                        singlechan = True
            # if the arrays are more than 1D, then go through each
            if len(self.spec.shape) > 1:
                for i in range(self.spec.shape[0]):
                    spec = self.spec[i]
                    if not havechan:
                        chan = np.arange(len(spec))
                    elif singlechan:
                        chan = self.chan
                    else:
                        chan = self.chan[i]
                    if singlefreq:
                        freq = self.freq
                    else:
                        freq = self.freq[i]
                    spectra.append(Spectrum(spec=spec, freq=freq, chans=chan))
            else:
                # construct the channel array if needed
                if not havechan:
                    self.chan = np.arange(len(self.spec))
                spectra.append(Spectrum(spec=self.spec, freq=self.freq, chans=self.chan))

        first = True
        images = {}

        # make images from the spectra
        for i, spec in enumerate(spectra):
            data = (spec.chans(masked=False), spec.freq(masked=False),
                    spec.spec(csub=False, masked=False))
            if first:
                table = Table(columns=["channel", "frequency", "flux"],
                              units=["number", "GHz", "Unknown"], data=np.column_stack(data),
                              planes=["0"])
                first = False
            else:
                table.addPlane(np.column_stack(data), "%i" % i)
            myplot = APlot(ptype=admit.PlotControl.PNG, pmode=admit.PlotControl.BATCH,
                                 abspath=os.getcwd())
            myplot.plotter(spec.freq(masked=False), [spec.spec(csub=False, masked=False)],
                           title="Spectrum %i" % i, figname="fig_%i" % i, xlab="Frequency",
                           ylab="Intensity", thumbnail=True)
            # Why not use p1 as the key?
            images["fig%i" % i] = myplot.getFigure(figno=myplot.figno, relative=True)
        image = Image(images=images, description="Spectra")
        # construct the BDP
        bdp = CubeSpectrum_BDP(image=image, table=table)

        return bdp
예제 #3
0
    def getfile(self, file):
        """ Method to read in a file and convert it to a Spectrum. Columns must already have been
            specified.

            Parameters
            ----------
            file : str
                Name of the file to read in

            Returns
            -------
            Spectrum instance containing the data read in from the file

        """
        # do some consistency and integrity checking
        if self.freqcol is None and self.velcol is None:
            raise Exception("Either the frequency column or velocity column must be specified.")
        if not isinstance(self.chancol, int):
            raise Exception("chan parameter must be an int.")
        if not isinstance(self.freqcol, int) and self.freqcol is not None:
            raise Exception("freq parameter must be an int.")
        if not isinstance(self.velcol, int) and self.velcol is not None:
            raise Exception("velocity parameter must be an int.")
        if not isinstance(self.speccol, int):
            raise Exception("spec parameter must be an int.")
        #if self.freqcol < 0 and self.freqcol is not None:
        #    raise Exception("The frequency column must be specified (i.e. freq=1)")
        if self.speccol < 0:
            raise Exception("The spectral column must be specified (i.e. spec=1)")
        print self.velcol
        if self.velcol >= 0:
            if self.restfreq is not None:
                if not isinstance(self.restfreq, float) and not isinstance(self.restfreq, int):
                    raise Exception("Restfreq must be a float.")
            else:
                raise Exception("Restfreq must be specified.")
            if self.vlsr is None:
                print "vlsr was not specified, assuming it is 0.0"
                self.vlsr = 0.0
            elif not isinstance(self.vlsr, float) and not isinstance(self.vlsr, int):
                raise Exception("vlsr must be a float")
        # find out the minimum number of columns to expect
        mincol = max(self.freqcol, self.chancol, self.speccol)

        # open the file and read it in
        fl = open(file, 'r')
        lines = fl.readlines()
        fl.close()

        # track line that are skipped for various reasons
        skipped = 0
        comments = 0
        blank = 0

        freq = []
        spec = []
        chan = []

        # go through each line
        for line in lines:
            # if the line is blank
            if len(line) < 1:
                blank += 1
                continue

            # if the line is a comment
            if line.startswith("#"):
                comments += 1
                continue

            # split the line up
            data = line.split(self.separator)

            # if there are not enough columns
            if len(data) < mincol:
                skipped += 1
                continue

            # add the data to the arrays
            if self.velcol >= 0:
                freq.append(float(data[self.velcol - 1]))
            else:
                freq.append(float(data[self.freqcol - 1]))
            spec.append(float(data[self.speccol - 1]))
            if self.chancol > 0:
                chan.append(int(data[self.chancol - 1]))
        if self.velcol >= 0:
            for i, frq in enumerate(freq):
                freq[i] = self.restfreq + utils.veltofreq(self.vlsr - frq, self.restfreq)

        # if the was no channel column the generate it
        if len(chan) == 0:
            chan = range(len(spec))

        # report what was found
        print "Imported %i lines from file %s" % (len(spec), file)
        if blank > 0:
            print "Skipped %i blank lines from file %s" % (blank, file)
        if skipped > 0:
            print "Skipped %i lines with too few columns from file %s" % (skipped, file)
        if comments > 0:
            print "Skipped %i commented lines from file %s" % (comments, file)
        if self.length == 0:
            self.length = len(spec)
        else:
            # if this spectrum is not the same length of the others
            if self.length != len(spec):
                raise Exception("Not all input spectra are the same length.")

        # convert to a Spectrum instance
        return Spectrum(spec=spec, freq=freq, chans=chan)
예제 #4
0
    def convert(self,
                chan=None,
                freq=None,
                velocity=None,
                spec=None,
                file=None,
                separator=None,
                restfreq=None,
                vlsr=None):
        """ Method to convert input data (either files or arrays) into a CubeSpectrum_BDP. If files
            are used then then the columns containing the frequency and the intensity must be given
            (channel numbers are optional). Any number of files can be given, but all spectra must
            have the same length as they are assumed to come from the same data source. Blank lines
            and lines starting with a comment '#' will be skipped, additionally any line with too
            few columns will be skipped. If arrays are used an input then both the frequency and
            intensity must be specified (the channel numbers are optional). Both lists and numpy
            arrays are accepted as inputs. Multidimmensional arrays are supported with the following
            parameters:

            + A single frequency list can be given to cover all input spectra, otherwise the shape
              of the frequency array must match that of the spectra
            + A single channel list can be given to cover all input spectra, otherwise the shape
              of the channel array must match that of the spectra
            + All spectra must have the same length

            If a channel array is not specified then one will be constructed with the following
            parameters:

            + The channel numbers will start at 0 (casa convention)
            + The first entry in the spectrum will be considered the first channel, regardless of
              whether the frequency array increases or decreases.

            Additionally, if there is velocity axis, but no frequency axis, a frequency axis can
            be constructed by specifying a rest frequency (restfreq), and vlsr.

            The convert method will return a single CubeSpectrum_BDP instance holding all input spectra
            along with an image of each.

            Parameters
            ----------
            chan : array or int
                An array holding the channel numbers for the data, multidimmensional arrays are
                supported. If an integer is specified then it is the number of the column
                in the file which contains the channel numbers, column numbers are 1 based.
                Default: None

            freq : array
                An array holding the frequencies for the data, multidimmensional arrays are
                supported. If an integer is specified then it is the number of the column
                in the file which contains the frequencies, column numbers are 1 based.
                Default: None

            velocity : array
                An array holding the velocity for the data, multidimmensional arrays are
                supported. If an integer is specified then it is the number of the column
                in the file which contains the velcoties, column numbers are 1 based. If this
                parameter is specified then restfreq and vlsr must also be specified.
                Default: None

            spec : array
                An array holding the intesities of the data, multidimmensional arrays are supported.
                If an integer is specified then it is the number of the column in the file which
                contains the intensities, column numbers are 1 based.
                Default: None

            file : list or str
                A single file name or a list of file names to be read in for spectra.
                Default: None

            separator : str
                The column separator for reading in the data files.
                Default: None (any whitespace)

            restfreq : float
                The rest frequency to use to convert the spectra from velocity to frequency units.
                The rest frequency is in GHz.
                Default: None (no conversion done)

            vlsr : float
                The reference velocity for converting a velocity axis to frequency. The units are
                km/s. If this is not set then it is assumed that the vlsr is 0.0.
                Default: None

            Returns
            -------
            CubeSpectrum_BDP instance containing all of the inpur spectra.

        """
        self.restfreq = restfreq
        self.vlsr = vlsr

        # if a string was given as the file name then turn it into a list so it can be iterated over
        if isinstance(file, str):
            self.file = [file]
        else:
            self.file = file
        # do some error checking
        if isinstance(chan, np.ndarray) or isinstance(chan, list):
            if isinstance(chan, list):
                self.chan = np.array(chan)
            else:
                self.chan = copy.deepcopy(chan)
            self.chancol = -1
        elif isinstance(chan, int):
            self.chancol = chan
            self.chan = None
        else:
            self.chancol = -1
            self.chan = None
        if isinstance(freq, np.ndarray) or isinstance(freq, list):
            if isinstance(freq, list):
                self.freq = np.array(freq)
            else:
                self.freq = copy.deepcopy(freq)
            self.freqcol = -1
        elif isinstance(freq, int):
            self.freqcol = freq
            self.freq = None
        else:
            self.freqcol = -1
            self.freq = None
        if isinstance(velocity, np.ndarray) or isinstance(velocity, list):
            if isinstance(velocity, list):
                self.freq = np.array(velocity, dtype=np.float)
            else:
                self.freq = velocity.astype(np.float)
            for i, frq in enumerate(self.freq):
                self.freq[i] = self.restfreq + utils.veltofreq(
                    frq - self.vlsr, self.restfreq)
            self.freqcol = -1
        elif isinstance(velocity, int):
            self.velcol = velocity
            self.velocity = None
        else:
            self.velcol = -1
            self.velocity = None
        if isinstance(spec, np.ndarray) or isinstance(spec, list):
            if isinstance(spec, list):
                self.spec = np.array(spec)
            else:
                self.spec = copy.deepcopy(spec)
            self.speccol = -1
        elif isinstance(spec, int):
            self.speccol = spec
            self.spec = None
        else:
            self.speccol = -1
            self.spec = None
        if isinstance(separator, str):
            self.separator = separator
        spectra = []
        # read in the data from any files
        if self.file:
            for fl in self.file:
                spectra.append(self.getfile(fl))
        else:
            # convert the input arrays
            singlefreq = False
            singlechan = False
            havechan = False
            # make sure they have the same shape or that the frequency array is 1D
            if self.spec.shape != self.freq.shape:
                if len(self.spec.shape) == 1 and len(self.freq.shape) != 1:
                    raise Exception(
                        "Frequency axis and spectral axis do not have the same shape."
                    )
                else:
                    singlefreq = True
            # make sure they have the same shape or that the channel array is 1D
            if self.chan:
                havechan = True
                if self.spec.shape != self.chan.shape:
                    if len(spec.shape) == 1 and len(self.chan.shape) != 1:
                        raise Exception(
                            "Channel axis and spectral axis do not have the same shape."
                        )
                    else:
                        singlechan = True
            # if the arrays are more than 1D, then go through each
            if len(self.spec.shape) > 1:
                for i in range(self.spec.shape[0]):
                    spec = self.spec[i]
                    if not havechan:
                        chan = np.arange(len(spec))
                    elif singlechan:
                        chan = self.chan
                    else:
                        chan = self.chan[i]
                    if singlefreq:
                        freq = self.freq
                    else:
                        freq = self.freq[i]
                    spectra.append(Spectrum(spec=spec, freq=freq, chans=chan))
            else:
                # construct the channel array if needed
                if not havechan:
                    self.chan = np.arange(len(self.spec))
                spectra.append(
                    Spectrum(spec=self.spec, freq=self.freq, chans=self.chan))

        first = True
        images = {}

        # make images from the spectra
        for i, spec in enumerate(spectra):
            data = (spec.chans(masked=False), spec.freq(masked=False),
                    spec.spec(csub=False, masked=False))
            if first:
                table = Table(columns=["channel", "frequency", "flux"],
                              units=["number", "GHz", "Unknown"],
                              data=np.column_stack(data),
                              planes=["0"])
                first = False
            else:
                table.addPlane(np.column_stack(data), "%i" % i)
            myplot = APlot(ptype=admit.PlotControl.PNG,
                           pmode=admit.PlotControl.BATCH,
                           abspath=os.getcwd())
            myplot.plotter(spec.freq(masked=False),
                           [spec.spec(csub=False, masked=False)],
                           title="Spectrum %i" % i,
                           figname="fig_%i" % i,
                           xlab="Frequency",
                           ylab="Intensity",
                           thumbnail=True)
            # Why not use p1 as the key?
            images["fig%i" % i] = myplot.getFigure(figno=myplot.figno,
                                                   relative=True)
        image = Image(images=images, description="Spectra")
        # construct the BDP
        bdp = CubeSpectrum_BDP(image=image, table=table)

        return bdp
예제 #5
0
    def getfile(self, file):
        """ Method to read in a file and convert it to a Spectrum. Columns must already have been
            specified.

            Parameters
            ----------
            file : str
                Name of the file to read in

            Returns
            -------
            Spectrum instance containing the data read in from the file

        """
        # do some consistency and integrity checking
        if self.freqcol is None and self.velcol is None:
            raise Exception(
                "Either the frequency column or velocity column must be specified."
            )
        if not isinstance(self.chancol, int):
            raise Exception("chan parameter must be an int.")
        if not isinstance(self.freqcol, int) and self.freqcol is not None:
            raise Exception("freq parameter must be an int.")
        if not isinstance(self.velcol, int) and self.velcol is not None:
            raise Exception("velocity parameter must be an int.")
        if not isinstance(self.speccol, int):
            raise Exception("spec parameter must be an int.")
        #if self.freqcol < 0 and self.freqcol is not None:
        #    raise Exception("The frequency column must be specified (i.e. freq=1)")
        if self.speccol < 0:
            raise Exception(
                "The spectral column must be specified (i.e. spec=1)")
        print self.velcol
        if self.velcol >= 0:
            if self.restfreq is not None:
                if not isinstance(self.restfreq, float) and not isinstance(
                        self.restfreq, int):
                    raise Exception("Restfreq must be a float.")
            else:
                raise Exception("Restfreq must be specified.")
            if self.vlsr is None:
                print "vlsr was not specified, assuming it is 0.0"
                self.vlsr = 0.0
            elif not isinstance(self.vlsr, float) and not isinstance(
                    self.vlsr, int):
                raise Exception("vlsr must be a float")
        # find out the minimum number of columns to expect
        mincol = max(self.freqcol, self.chancol, self.speccol)

        # open the file and read it in
        fl = open(file, 'r')
        lines = fl.readlines()
        fl.close()

        # track line that are skipped for various reasons
        skipped = 0
        comments = 0
        blank = 0

        freq = []
        spec = []
        chan = []

        # go through each line
        for line in lines:
            # if the line is blank
            if len(line) < 1:
                blank += 1
                continue

            # if the line is a comment
            if line.startswith("#"):
                comments += 1
                continue

            # split the line up
            data = line.split(self.separator)

            # if there are not enough columns
            if len(data) < mincol:
                skipped += 1
                continue

            # add the data to the arrays
            if self.velcol >= 0:
                freq.append(float(data[self.velcol - 1]))
            else:
                freq.append(float(data[self.freqcol - 1]))
            spec.append(float(data[self.speccol - 1]))
            if self.chancol > 0:
                chan.append(int(data[self.chancol - 1]))
        if self.velcol >= 0:
            for i, frq in enumerate(freq):
                freq[i] = self.restfreq + utils.veltofreq(
                    self.vlsr - frq, self.restfreq)

        # if the was no channel column the generate it
        if len(chan) == 0:
            chan = range(len(spec))

        # report what was found
        print "Imported %i lines from file %s" % (len(spec), file)
        if blank > 0:
            print "Skipped %i blank lines from file %s" % (blank, file)
        if skipped > 0:
            print "Skipped %i lines with too few columns from file %s" % (
                skipped, file)
        if comments > 0:
            print "Skipped %i commented lines from file %s" % (comments, file)
        if self.length == 0:
            self.length = len(spec)
        else:
            # if this spectrum is not the same length of the others
            if self.length != len(spec):
                raise Exception("Not all input spectra are the same length.")

        # convert to a Spectrum instance
        return Spectrum(spec=spec, freq=freq, chans=chan)
예제 #6
0
    def run(self):
        """Runs the task.

           Parameters
           ----------
           None

           Returns
           -------
           None
        """

        self._summary = {}
        dt = utils.Dtime("CubeSpectrum")
        seed = self.getkey("seed")
        if seed <= 0:
            np.random.seed()
        else:
            np.random.seed(seed)
        #print "RANDOM.GET_STATE:",np.random.get_state()
        contin = self.getkey("contin")
        rms = 1.0  # not a user parameter, we do all spectra in S/N space
        f0 = self.getkey("freq")  # central frequency in band
        df = self.getkey("delta") / 1000.0  # channel width (in GHz)
        nspectra = self.getkey("nspectra")
        taskargs = " contin=%f freq=%f delta=%f nspectra=%f " % (contin, f0,
                                                                 df, nspectra)
        spec = range(nspectra)
        dt.tag("start")
        if self.getkey("file") != "":
            print "READING spectrum from", self.getkey("file")
            (freq, spec[0]) = getspec(self.getkey("file"))
            nchan = len(freq)
            print "Spectrum %d chans from %f to %f: min/max = %f %f" % (
                nchan, freq.min(), freq.max(), spec[0].min(), spec[0].max())
            # @todo nspectra>1 not tested
            for i in range(1, nspectra):
                spec[i] = deepcopy(spec[0])
            dt.tag("getspec")
        else:
            nchan = self.getkey("nchan")
            freq = np.arange(nchan, dtype=np.float64)
            center = int(nchan / 2)
            for i in range(nchan):
                freq[i] = f0 + (float((i - center)) * df)
            for i in range(nspectra):
                spec[i] = np.zeros(nchan)
        chans = np.arange(nchan)
        taskargs += " nchan = %d" % nchan
        for i in range(nspectra):
            if seed >= 0:
                spec[i] += np.random.normal(contin, rms, nchan)
#            print "MEAN/STD",spec[i].mean(),spec[i].std()
        lines = self.getkey("lines")
        sls = SpectralLineSearch(False)
        for item in self.getkey("transitions"):
            kw = {
                "include_only_nrao": True,
                "line_strengths": ["ls1", "ls2"],
                "energy_levels": ["el2", "el4"],
                "fel": True,
                "species": item[0]
            }
            results = sls.search(item[1][0], item[1][1], "off", **kw)
            # look at line strengths
            if len(results) > 0:
                mx = 0.0
                indx = -1
                for i in range(len(results)):
                    if results[i].getkey("linestrength") > mx:
                        indx = i
                        mx = results[i].getkey("linestrength")
                for res in results:
                    if mx > 0.0:
                        lines.append([
                            item[2] * res.getkey("linestrength") / mx,
                            res.getkey("frequency") +
                            utils.veltofreq(item[4], res.getkey("frequency")),
                            item[3]
                        ])
                    else:
                        lines.append([
                            item[2],
                            res.getkey("frequency") +
                            utils.veltofreq(item[4], res.getkey("frequency")),
                            item[3]
                        ])
        for item in lines:
            for i in range(nspectra):
                spec[i] += utils.gaussian1D(freq, item[0], item[1],
                                            utils.veltofreq(item[2], item[1]))

        if self.getkey("hanning"):
            for i in range(nspectra):
                filter = Filter1D.Filter1D(spec[i], "hanning", **{"width": 3})
                spec[i] = filter.run()
            dt.tag("hanning")
        center = int(nchan / 2)
        dt.tag("open")
        bdp_name = self.mkext("Genspec", "csp")
        b2 = CubeSpectrum_BDP(bdp_name)
        self.addoutput(b2)
        images = {}  # png's accumulated
        for i in range(nspectra):
            sd = []
            caption = "Generated Spectrum %d" % i
            # construct the Table for CubeSpectrum_BDP
            # @todo note data needs to be a tuple, later to be column_stack'd
            labels = ["channel", "frequency", "flux"]
            units = ["number", "GHz", ""]
            data = (chans, freq, spec[i])

            # plane 0 : we are allowing a multiplane table, so the first plane is special
            if i == 0:
                table = Table(columns=labels,
                              units=units,
                              data=np.column_stack(data),
                              planes=["0"])
            else:
                table.addPlane(np.column_stack(data), "%d" % i)
            # example plot , one per position for now
            x = chans
            xlab = 'Channel'
            y = [spec[i]]
            sd.append(xlab)

            myplot = APlot(ptype=self._plot_type,
                           pmode=self._plot_mode,
                           abspath=self.dir())
            ylab = 'Flux'
            p1 = "%s_%d" % (bdp_name, i)
            myplot.plotter(x, y, "", p1, xlab=xlab, ylab=ylab, thumbnail=True)
            # Why not use p1 as the key?
            ii = images["pos%d" % i] = myplot.getFigure(figno=myplot.figno,
                                                        relative=True)
            thumbname = myplot.getThumbnail(figno=myplot.figno, relative=True)

            image = Image(images=images, description="CubeSpectrum")
            sd.extend([ii, thumbname, caption])
            self.spec_description.append(sd)

        self._summary["spectra"] = SummaryEntry(self.spec_description,
                                                "GenerateSpectrum_AT",
                                                self.id(True), taskargs)

        dt.tag("table")
        b2.setkey("image", image)
        b2.setkey("table", table)
        b2.setkey("sigma", rms)
        b2.setkey("mean", contin)

        dt.tag("done")
        dt.end()
예제 #7
0
def findpatterns(spec, points, segments):
    """ Method to search for patterns in the peaks. Specifically it is
        looking for pairs of peaks that are the same distance apart (within
        the tolerance). These can be an indicator of rotation/infall/etc.
        Only two patterns are allowed to overlap. See the design documentation
        for specifics

        Parameters
        ----------
        spec : array like
            The spectrum that is currently being worked on.

        points : numpy array
            Listing of peak points

        segments : list
            List of the segments for the current spectrum

        Returns
        -------
        A Peaks class containing the spectra, segments, peaks and patterns
    """
    #self.dt.tag("START PATTERN")
    # initialize the data class
    peaks = Peaks(spec=spec, segments=segments)
    delfrq = utils.veltofreq(650, spec.freq()[len(spec)/2])
    maxsep = delfrq / spec.delta()
    ts = np.zeros(len(spec)).astype(float)
    ts[0] = 1.

    # make a copy of the input points which will be modified as groups are located
    singles = copy.deepcopy(points)
    # create a 2D array to catalog the distances between every peak
    diffs = np.zeros((len(points), len(points)))
    # calculate the distance between every peak
    #self.dt.tag("P0")

    for i in range(len(points)):
        for j in range(i + 1, len(points)):
            diffs[i, j] = abs(points[i] - points[j])
    #self.dt.tag("P1")
    # look for pairs of peaks that are a common distance apart (within the
    # given tolerance)
    clusters = {}
    for i in range(len(points)):
        for j in range(i + 1, min(len(points), i + 2)):
            # get each distance one at a time and compare it to the rest
            diff = diffs[i, j]
            dlist = []
            # if this is the first time this distance has been found
            first = True
            for k in range(i + 1):
                for l in range(k + 1, min(len(points), k + 2)):
                    #print i, j, k, l
                    # compare to all other points, skipping itself
                    if (k == i and l == j) or diffs[k, l] < 3.0 / 3.0 \
                       or abs(spec.spec()[points[k]]) > 2.0 * abs(spec.spec()[points[l]])\
                       or abs(spec.spec()[points[l]]) > 2.0 * abs(spec.spec()[points[k]]):
                        continue
                    # if the distances from two pairs of points are close enough
                    # add it to the list of clusters
                    if maxsep > diffs[k, l] > 0.0 and (diff - 3.0 / 3.0 < diffs[k, l] < diff + 3.0 / 3.0):
                        # if this is the first time for this distance then add
                        # both to the list
                        if first:
                            dlist.append([i, j])
                        dlist.append([k, l])
                        # mark the current point as processed (i.e. set to 0.0)
                        diffs[k, l] = 0.0
                        first = False
            # if groups of points were detected then add them to the dictionary
            if len(dlist) > 0:
                clusters[diff] = dlist
    #self.dt.tag("P2")
    # get the actual peak points rather then just indexes
    clens = {}
    for k, v in clusters.iteritems():
        tl = []
        for i in v:
            tl.append([points[i[0]], points[i[1]]])
        clusters[k] = tl
        clens[k] = len(tl)
    # sort the list to make it easier to process
    clist = sorted(clens, key=clens.get)
    clist.reverse()

    spoints = []
    for k in clist:
        for i in clusters[k]:
            if not i[0] in spoints:
                spoints.append(i[0])
            if not i[1] in spoints:
                spoints.append(i[1])
    # single spectral lines
    # spectral lines that appear to be in a pattern
    for p in spoints:
        l = set()
        for k in clist:
            v = clusters[k]
            # collect those that are very close together
            for i in v:
                if (p - 0.1 < i[0] < p + 0.1) or (p - 0.1 < i[1] < p + 0.1):
                    l.add(k)
        # reduce each of these to a single instance
        if len(l) > 1:
            for i in clist:
                if i in l:
                    l.remove(i)
                    break
            for i in l:
                for j in range(len(clusters[i]) - 1, -1, -1):
                    if (p - 0.1 < clusters[i][j][0] < p + 0.1) or \
                       (p - 0.1 < clusters[i][j][1] < p + 0.1):
                        del clusters[i][j]
                if len(clusters[i]) < 2:
                    del clusters[i]
                    clist.remove(i)
    # remove any that appear multiple times
    counts = {}
    multi = {}
    for k, v in clusters.iteritems():
        for i in v:
            if i[0] in counts:
                multi[i[0]].append(i)
            else:
                counts[i[0]] = 1
                multi[i[0]] = [i]
            if i[1] in counts:
                multi[i[1]].append(i)
            else:
                counts[i[1]] = 1
                multi[i[1]] = [i]
    for k, v in multi.iteritems():
        ratios = {}
        r = []
        if len(v) > 1:
            for i in v:
                temp = max(peaks.getspecs()[i[0]], peaks.getspecs()[i[1]]) / \
                       min(peaks.getspecs()[i[0]], peaks.getspecs()[i[1]])
                r.append(temp)
                ratios[tuple(i)] = temp
            best = min(r, key=lambda x: abs(x - 1.0))
            for k1, v1 in ratios.iteritems():
                if best != v1:
                    for k2 in clusters.keys():
                        try:
                            clusters[k2].remove(list(k1))
                        except ValueError:
                            pass
    remove = []
    newcounts = {}
    counts = set()
    for k, v in clusters.iteritems():
        #newcounts[k] = len(v)
        counts.add(len(v))
    if len(counts) > 0:
        counts = sorted(counts)
        counts.reverse()
        counts = counts[0:min(2, len(counts))]
    for k, v in clusters.iteritems():
        if not len(v) in counts:
            remove.append(k)
            continue
        else:
            newcounts[k] = len(v)
        for i in v:
            for j in i:
                try:
                    singles.remove(j)
                except ValueError:
                    pass

    for i in remove:
        del clusters[i]

    peaks.singles = singles
    peaks.pairs = clusters
    peaks.counts = newcounts
    return peaks
예제 #8
0
    def run(self):
        """Runs the task.

           Parameters
           ----------
           None

           Returns
           -------
           None
        """

        self._summary = {}
        dt = utils.Dtime("CubeSpectrum")
        seed = self.getkey("seed")
        if seed <= 0:
            np.random.seed()
        else:
            np.random.seed(seed)
        #print "RANDOM.GET_STATE:",np.random.get_state()
        contin = self.getkey("contin")
        rms = 1.0        # not a user parameter, we do all spectra in S/N space
        f0 = self.getkey("freq")     # central frequency in band
        df = self.getkey("delta") / 1000.0      # channel width (in GHz)
        nspectra = self.getkey("nspectra")
        taskargs = " contin=%f freq=%f delta=%f nspectra=%f " % (contin,f0,df,nspectra)
        spec = range(nspectra)
        dt.tag("start")
        if self.getkey("file") != "":
            print "READING spectrum from",self.getkey("file") 
            (freq, spec[0]) = getspec(self.getkey("file"))
            nchan = len(freq)
            print "Spectrum %d chans from %f to %f: min/max = %f %f" % (nchan, freq.min(), freq.max(), spec[0].min(), spec[0].max())
            # @todo nspectra>1 not tested
            for i in range(1,nspectra):
                spec[i] = deepcopy(spec[0])
            dt.tag("getspec")                
        else:
            nchan = self.getkey("nchan")
            freq = np.arange(nchan, dtype=np.float64)
            center = int(nchan/2)
            for i in range(nchan):
                freq[i] = f0 + (float((i - center)) * df)
            for i in range(nspectra):
                spec[i] = np.zeros(nchan)
        chans = np.arange(nchan)
        taskargs += " nchan = %d" % nchan
        for i in range(nspectra):
            if seed >= 0:
                spec[i] += np.random.normal(contin, rms, nchan)
#            print "MEAN/STD",spec[i].mean(),spec[i].std()
        lines = self.getkey("lines")
        sls = SpectralLineSearch(False)
        for item in self.getkey("transitions"):
            kw = {"include_only_nrao" : True,
                  "line_strengths": ["ls1", "ls2"],
                  "energy_levels" : ["el2", "el4"],
                  "fel" : True,
                  "species" : item[0]
                  }
            results = sls.search(item[1][0], item[1][1], "off", **kw)
            # look at line strengths
            if len(results) > 0:
                mx = 0.0
                indx = -1
                for i in range(len(results)):
                    if results[i].getkey("linestrength") > mx:
                        indx = i
                        mx = results[i].getkey("linestrength")
                for res in results:
                    if mx > 0.0:
                        lines.append([item[2] * res.getkey("linestrength") / mx, res.getkey("frequency") +
                                      utils.veltofreq(item[4], res.getkey("frequency")), item[3]])
                    else:
                        lines.append([item[2], res.getkey("frequency") + utils.veltofreq(item[4], 
                                      res.getkey("frequency")), item[3]])
        for item in lines:
            for i in range(nspectra):
                spec[i] += utils.gaussian1D(freq, item[0], item[1], utils.veltofreq(item[2], item[1]))

        if self.getkey("hanning"):
            for i in range(nspectra):
                filter = Filter1D.Filter1D(spec[i], "hanning", **{"width" : 3})
                spec[i] = filter.run()
            dt.tag("hanning")
        center = int(nchan/2)
        dt.tag("open")
        bdp_name = self.mkext("Genspec","csp")
        b2 = CubeSpectrum_BDP(bdp_name)
        self.addoutput(b2)
        images = {}                                      # png's accumulated
        for i in range(nspectra):
            sd = []
            caption = "Generated Spectrum %d" % i
            # construct the Table for CubeSpectrum_BDP 
            # @todo note data needs to be a tuple, later to be column_stack'd
            labels = ["channel" ,"frequency" ,"flux" ]
            units  = ["number"  ,"GHz"       ,""   ]
            data   = (chans     ,freq       ,spec[i]   )

            # plane 0 : we are allowing a multiplane table, so the first plane is special
            if i==0:
                table = Table(columns=labels,units=units,data=np.column_stack(data),planes=["0"])
            else:
                table.addPlane(np.column_stack(data),"%d" % i)
            # example plot , one per position for now
            x = chans
            xlab  = 'Channel'
            y = [spec[i]]
            sd.append(xlab)

            myplot = APlot(ptype=self._plot_type,pmode=self._plot_mode, abspath=self.dir())
            ylab  = 'Flux'
            p1 = "%s_%d" % (bdp_name,i)
            myplot.plotter(x,y,"",p1,xlab=xlab,ylab=ylab,thumbnail=True)
            # Why not use p1 as the key?
            ii = images["pos%d" % i] = myplot.getFigure(figno=myplot.figno,relative=True)
            thumbname = myplot.getThumbnail(figno=myplot.figno,relative=True)

            image = Image(images=images, description="CubeSpectrum")
            sd.extend([ii, thumbname, caption])
            self.spec_description.append(sd)

        self._summary["spectra"] = SummaryEntry(self.spec_description,"GenerateSpectrum_AT",self.id(True), taskargs)
        

        dt.tag("table")
        b2.setkey("image",image)
        b2.setkey("table",table)
        b2.setkey("sigma",rms)
        b2.setkey("mean",contin)

        dt.tag("done")
        dt.end()