Exemplo n.º 1
0
    def get_time(self):
        time = plane.Time()

        lower = 1.0
        upper = 2.0
        lower1 = 1.1
        upper1 = 2.1
        lower2 = 1.2
        upper2 = 2.2
        samples = [
            shape.SubInterval(lower, lower1),
            shape.SubInterval(lower2, upper),
            shape.SubInterval(upper1, upper2)
        ]

        interval = shape.Interval(lower, upper2, samples)

        time.bounds = interval
        if self.caom_version >= 24:
            time.resolution_bounds = shape.Interval(22.2, 33.3)
        time.dimension = 1
        time.resolution = 2.1
        time.sample_size = 3.0
        time.exposure = 10.3

        return time
Exemplo n.º 2
0
    def get_energy(self):
        energy = plane.Energy()

        lower = 1.0
        upper = 2.0
        lower1 = 1.1
        upper1 = 2.1
        lower2 = 1.2
        upper2 = 2.2
        samples = [
            shape.SubInterval(lower, lower1),
            shape.SubInterval(lower2, upper),
            shape.SubInterval(upper1, upper2)
        ]

        interval = shape.Interval(lower, upper2, samples)

        energy.bounds = interval
        energy.dimension = 100
        energy.resolving_power = 2.0
        energy.sample_size = 1.1
        energy.bandpass_name = "e"
        if self.caom_version >= 24:
            energy.energy_bands.add(plane.EnergyBand.GAMMARAY)
            energy.energy_bands.add(plane.EnergyBand.OPTICAL)
        energy.transition = wcs.EnergyTransition("species", "transition")

        return energy
Exemplo n.º 3
0
    def function1d_to_interval(temporal_wcs, function_1d):
        try:
            TimeUtil.validate_wcs(temporal_wcs)
            # // TODO: (comment pulled from Java code):
            # if mjdref has a value then the units of axis values could be
            # any time
            # // units, like days, hours, minutes, seconds, and smaller
            # // since they are offsets from mjdref

            p1 = float(0.5)
            p2 = float(function_1d.naxis + 0.5)
            a = pix2val(function_1d, p1)
            b = pix2val(function_1d, p2)
            if function_1d.delta < 0.0:
                raise ValueError(
                    '{} delta must be greater than 0.0'.format(function_1d))

            if temporal_wcs.mjdref is not None:
                a += float(temporal_wcs.mjdref)
                b += float(temporal_wcs.mjdref)

            return shape.SubInterval(min(a, b), max(a, b))

        except Exception as ex:
            raise ValueError("Invalid function in Temporal WCS: {}".format(
                repr(ex)))
Exemplo n.º 4
0
def build_time(override, almaca_name):

    # HK 05-09-19
    # For the time dimension:
    # - resolution: this is far less clear to me, but I think in principle,
    # once could try to make an image using some time-based subset of the full
    # measurement set.  So in principle, I suppose one could make [sampleSize]
    # independent images.  In practice, there probably would be insufficient
    # data to actually make decent images for such a small subset of the
    # data.  Something like the number of times that the source is observed in
    # between calibrators would probably be a more appropriate / practical
    # level of time sampling, but I don't think there would be an easy way to
    # pull that information out of the metadata.  The time resolution value
    # could be listed as 'null' to avoid the confusion.
    resolution = None

    start_date = mc.to_float(override.get('start_date'))
    end_date = mc.to_float(override.get('end_date'))

    # HK 14-08-09
    # If 'exposure' is supposed to be the total (useful) exposure time
    # on-source, then this parameter should be msmd.effexposuretime().
    # The 'itime' parameter calculated in get_msmd.py gives a larger
    # value, as I believe it includes the full time on-source, regardless
    # of what mode the data is being taken in.
    exposure_time = mc.to_float(override.get('effexposuretime'))

    time_bounds = Interval(start_date,
                           end_date,
                           samples=[shape.SubInterval(start_date, end_date)])
    return Time(bounds=time_bounds,
                dimension=1,
                resolution=resolution,
                sample_size=mc.to_float(override.get('time_sample_size')),
                exposure=exposure_time)
Exemplo n.º 5
0
    def function1d_to_interval(temporal_wcs, function_1d):
        try:
            TimeUtil.validate_wcs(temporal_wcs)
            # // TODO: (comment pulled from Java code):
            # if mjdref has a value then the units of axis values could be
            # any time
            # // units, like days, hours, minutes, seconds, and smaller
            # // since they are offsets from mjdref

            # PD - 16-04-20
            # technically there is nothing wrong with a WCS axis that
            # decreases in coord values while increasing in pixel values
            # (it's just a line with negative slope).
            #
            # the computation of the time bounds interval sorts out the
            # min/max so it also doesn't care about the "direction"

            p1 = float(0.5)
            p2 = float(function_1d.naxis + 0.5)
            a = pix2val(function_1d, p1)
            b = pix2val(function_1d, p2)

            if temporal_wcs.mjdref is not None:
                a += float(temporal_wcs.mjdref)
                b += float(temporal_wcs.mjdref)

            return shape.SubInterval(min(a, b), max(a, b))

        except Exception as ex:
            raise ValueError("Invalid function in Temporal WCS: {}".format(
                repr(ex)))
Exemplo n.º 6
0
def build_plane_time_sample(start_date, end_date):
    """Create a SubInterval for the plane-level bounding box for time, given
    the start and end dates.
    :param start_date minimum date
    :param end_date maximum date."""
    start_date.format = 'mjd'
    end_date.format = 'mjd'
    return caom_shape.SubInterval(
        mc.to_float(start_date.value),
        mc.to_float(end_date.value),
    )
Exemplo n.º 7
0
    def range1d_to_interval(range_1d):
        a = float(range_1d.start.val)
        b = float(range_1d.end.val)
        #  The energy converter work done in the Java code is skipped here.
        #  Doing it here introduced some precision errors which lead to false invalids.
        #  Ignoring the units for validation sounds like it's ok, as long as the
        #  same values come out of the p2s, s2p calculations in the main validator
        #  code. It's assumed that doing the conversions in the native units is
        #  sufficient, as long as the values are the same after p2s -> s2p is done.

        return shape.SubInterval(min(a, b), max(a, b))
Exemplo n.º 8
0
    def range1d_to_interval(temporal_wcs, axis_1d):
        TimeUtil.validate_wcs(temporal_wcs)

        # TODO: (comment pulled from Java code):
        # if mjdref has a value then the units of axis values could be any time
        # units, like days, hours, minutes, seconds, and smaller
        # since they are offsets from mjdref
        a = axis_1d.getStart().val
        b = axis_1d.getEnd().val
        if temporal_wcs.mjdref is not None:
            a += float(temporal_wcs.mjdref)
            b += float(temporal_wcs.mjdref)

        return shape.SubInterval(min(a, b), max(a, b))
Exemplo n.º 9
0
    def range1d_to_interval(temporal_wcs, range_1d):
        TimeUtil.validate_wcs(temporal_wcs)

        # TODO: (comment pulled from Java code):
        # if mjdref has a value then the units of axis values could be any time
        # units, like days, hours, minutes, seconds, and smaller
        # since they are offsets from mjdref
        a = range_1d.start.val
        b = range_1d.end.val
        if b < a:
            raise ValueError("range.end not >= range.start in Temporal WCS")

        if temporal_wcs.mjdref is not None:
            a += float(temporal_wcs.mjdref)
            b += float(temporal_wcs.mjdref)

        return shape.SubInterval(min(a, b), max(a, b))
Exemplo n.º 10
0
 def function1d_to_interval(temporal_wcs):
     naxis = temporal_wcs.axis.function.naxis
     p1 = 0.5
     p2 = naxis + 0.5
     return shape.SubInterval(p1, p2)
Exemplo n.º 11
0
def build_energy(override):

    spectral_windows = override.get('spectral_windows')
    sample_size = mc.to_float(override.get('energy_sample_size'))

    # HK 19-08-19
    # I'm still not quite sure that I follow this one.  I understand your
    # point from earlier about merging together overlapping wavelength
    # ranges, and that should be fine, although it might hide some
    # important information in the energy:resolution parameter, since
    # each of the overlapping ranges may have different spectral
    # resolutions.  By my approximate calculations, the 4 wavelength
    # ranges covered are 0.00259 to 0.00263, 0.00263 to 0.00267, 0.0026025
    # to 0.0026038, and 0.0026018 to 0.0026044.  If I were to merge those,
    # I would get 0.00259 to 0.00267.  I don't understand how the caom2
    # model lists 0.00259 to 0.002602 and then 0.002626 and 0.002672.
    # Specifically, the wavelengths covered by the first of the 4 ranges
    # I list, already span a much larger range than the first range listed
    # in caom2.

    energy = Energy()
    energy.em_band = EnergyBand.MILLIMETER
    energy.dimension = 1

    wvlns = []
    mid_wvln = []

    for spw in spectral_windows:
        wvln = numpy.array((_from_hz_to_m(spw[0]), _from_hz_to_m(spw[1])))
        wvlns.append(wvln)
        mid_wvln.append(wvln[0] + wvln[1])
    order = numpy.argsort(mid_wvln)

    min_bound = None
    max_bound = None
    si = []
    for idx in order:
        lower = min(wvlns[idx])
        upper = max(wvlns[idx])

        si = _add_subinterval(si, (lower, upper))
        if min_bound is not None:
            min_bound = min(min_bound, lower)
        else:
            min_bound = lower
        if max_bound is not None:
            max_bound = max(max_bound, upper)
        else:
            max_bound = upper

    samples = []
    for s in si:
        samples.append(shape.SubInterval(s[0], s[1]))

    energy.bounds = Interval(min_bound, max_bound, samples=samples)

    # HK 15-10-19
    #
    # It looks like the caom2 model puts energy in wavelength units (I'm not
    # clear whether that is metres or centimetres?), whereas the numbers
    # I quoted above are directly from msmd and are given in frequency units
    # of Hertz.  I'm not sure what level of precision you would use for the
    # conversion, but here's roughly what you'd want to do:
    #
    # [resolution in wavelength units] / [central wavelength] =
    # [resolution in frequency units] /[central frequency]
    #
    # Using [central wavelength] = [speed of light] / [central frequency], and
    # a speed of light of 2.9979e8 m/s (or whatever precision you need, and
    # convert to cm/s if needed), you should be able to run the calculation
    # with values you've already extracted.  For a central frequency of
    # 113GHz, I get a value of about 3.7e-7 m, assuming I've done my quick
    # calculation correctly.
    #
    # NB: since both the sampleSize and resolution parameters are looking at a
    # differential wavelength measurement, both conversions would follow the
    # same formula as I've written.
    #
    mean_frequency = (_from_m_to_hz(min_bound) + _from_m_to_hz(max_bound)) / 2
    energy.sample_size = _delta_hz_to_m(sample_size, mean_frequency)
    energy_resolution = mc.to_float(override.get('energy_resolution'))

    # HK 03-12-19
    # resolving power is unit-less
    # ResolvingPower = mean[frequency_Hz] / chanres_Hz
    energy.resolving_power = mean_frequency / energy_resolution

    # HK 3-10-19
    # energy: bandpassName: could this also be Band3?  (I know it is already
    # listed under 'instrument' in the top level plane)
    energy.bandpass_name = _get_band_name(override)
    return energy