Ejemplo n.º 1
0
def test_apply_bda(fake_data):
    """Generate test data and make sure that BDA is applied correctly."""
    uvd = fake_data

    # define parameters
    max_decorr = 0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = Angle(20.0, units.deg)
    max_time = 30 * units.s
    uvd2 = bda_tools.apply_bda(
        uvd,
        max_decorr,
        pre_fs_int_time,
        corr_fov_angle,
        max_time,
    )

    # make sure that things are correct
    assert uvd2.Ntimes == 3
    assert uvd2.Nbls == 3
    assert uvd2.Nblts == 5  # baselines (0, 1) and (0, 2) were all averaged together
    bl1_inds, _, _ = uvd._key2inds((0, 1))
    bl2_inds, _, _ = uvd2._key2inds((0, 1))
    target = uvd2.data_array[bl2_inds]
    # multiply in factor of 3 to account for 3 time samples being averaged
    avg_data = 3.0 * np.average(uvd.data_array[bl1_inds],
                                axis=0)[np.newaxis, :, :, :]
    # there are small differences to account for phasing considerations, but the
    # results are still "close" for the times and baseline lengths chosen
    assert np.allclose(target, avg_data, atol=1e-3)

    return
Ejemplo n.º 2
0
def test_apply_bda_non_increasing_error(fake_data):
    """Test error when times in object are not monotonically increasing."""
    # mess with fake data
    uvd = fake_data
    uvd.time_array = uvd.time_array[::-1]
    max_decorr = 0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = Angle(20.0, units.degree)
    max_time = 30 * units.s

    with pytest.raises(AssertionError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
        )
    assert str(cm.value).startswith(
        "times of uvdata object are not monotonically increasing")
    return
Ejemplo n.º 3
0
def test_apply_bda_max_decorr_error():
    """Test error for supplying an invalid max_decorr value."""
    # define parameters
    uvd = UVData()
    max_decorr = -0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = Angle(20.0, units.degree)
    max_time = 30 * units.s
    corr_int_time = 2 * units.s

    # use a bad max_decorr value
    with pytest.raises(ValueError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
            corr_int_time,
        )
    assert str(cm.value).startswith("max_decorr must be between 0 and 1")
    return
Ejemplo n.º 4
0
def test_apply_bda_ind2_key_error(fake_data):
    """Test error when the length of ind2 is non-zero."""
    # mess with fake data
    uvd = fake_data
    uvd.ant_1_array[1] = 1
    uvd.ant_2_array[1] = 0
    max_decorr = 0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = Angle(20.0, units.degree)
    max_time = 30 * units.s
    corr_int_time = 2.0 * units.s

    with pytest.raises(AssertionError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
            corr_int_time,
        )
    assert str(cm.value).startswith("ind2 from _key2inds() is not 0--exiting")
    return
Ejemplo n.º 5
0
def test_apply_bda_phased_error(fake_data):
    """Test error when applying bda to phased data."""
    # convert input data to phased
    uvd = fake_data
    uvd.phase_to_time(uvd.time_array[0])
    max_decorr = 0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = Angle(20.0, units.degree)
    max_time = 30 * units.s
    corr_int_time = 2.0 * units.s

    with pytest.raises(ValueError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
            corr_int_time,
        )
    assert str(cm.value).startswith(
        "UVData object must be in drift mode to apply BDA")
    return
Ejemplo n.º 6
0
def test_apply_bda_corr_int_time_bad_quantity_error():
    """Test error for using an incompatible quantity for corr_int_time."""
    # define parameters
    uvd = UVData()
    max_decorr = 0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = Angle(20.0, units.degree)
    max_time = 30 * units.s
    corr_int_time = 2.0 * units.m

    # use a bad quantity for corr_int_time
    with pytest.raises(ValueError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
            corr_int_time,
        )
    assert str(cm.value).startswith(
        "corr_int_time must be a Quantity with units of time")
    return
Ejemplo n.º 7
0
def test_apply_bda_corr_int_time_float_error():
    """Test error for using corr_int_time as a float."""
    # define parameters
    uvd = UVData()
    max_decorr = 0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = Angle(20.0, units.degree)
    max_time = 30 * units.s
    corr_int_time = 2.0

    # use a plain float for corr_int_time
    with pytest.raises(ValueError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
            corr_int_time,
        )
    assert str(
        cm.value).startswith("corr_int_time must be an astropy.units.Quantity")
    return
Ejemplo n.º 8
0
def test_apply_bda_pre_fs_int_time_float_error():
    """Test error for not using a Quantity for pre_fs_int_time."""
    # define parameters
    uvd = UVData()
    max_decorr = 0.1
    pre_fs_int_time = 0.1
    corr_fov_angle = Angle(20.0, units.degree)
    max_time = 30 * units.s
    corr_int_time = 2 * units.s

    # pass in pre_fs_int_time as a float instead of a Quantity
    with pytest.raises(ValueError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
            corr_int_time,
        )
    assert str(cm.value).startswith(
        "pre_fs_int_time must be an astropy.units.Quantity")
    return
Ejemplo n.º 9
0
def test_apply_bda_non_angle_error():
    """Test error for not using an Angle for corr_fov_angle."""
    # define parameters
    uvd = UVData()
    max_decorr = 0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = "foo"
    max_time = 30 * units.s
    corr_int_time = 2 * units.s

    # test using something besides an angle for corr_fov_angle
    with pytest.raises(ValueError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
            corr_int_time,
        )
    assert str(cm.value).startswith(
        "corr_fov_angle must be an Angle object from astropy.coordinates")
    return
Ejemplo n.º 10
0
def test_apply_bda_non_uvd_error():
    """Test error for not using a UVData object."""
    # define parameters
    uvd = "foo"
    max_decorr = 0.1
    pre_fs_int_time = 0.1 * units.s
    corr_fov_angle = Angle(20.0, units.degree)
    max_time = 30 * units.s
    corr_int_time = 2 * units.s

    # test using something besides a UVData object
    with pytest.raises(ValueError) as cm:
        bda_tools.apply_bda(
            uvd,
            max_decorr,
            pre_fs_int_time,
            corr_fov_angle,
            max_time,
            corr_int_time,
        )
    assert str(cm.value).startswith(
        "apply_bda must be passed a UVData object as its first argument")
    return
Ejemplo n.º 11
0
args = ap.parse_args()

if os.path.exists(args.file_out) and args.overwrite is False:
    print("{} exists. Use --overwrite to overwrite the file.".format(
        args.file_out))
    sys.exit(0)

# check that output filetype is valid
if args.filetype not in ("uvh5", "uvfits", "miriad"):
    print("filetype must be one of uvh5, uvfits, or miriad")
    sys.exit(0)

# read in file
uv = UVData()
uv.read(args.file_in)

# apply BDA
pre_fs_int_time = args.pre_fs_int_time * units.s
corr_fov_angle = Angle(args.corr_fov_angle, units.deg)
max_time = args.max_time * units.s
uv2 = bda_tools.apply_bda(uv, args.max_decorr, pre_fs_int_time, corr_fov_angle,
                          max_time, args.corr_int_time)

# write out file
if args.filetype == "uvh5":
    uv2.write_uvh5(args.file_out, clobber=True)
if args.filetype == "uvfits":
    uv2.write_uvfits(args.file_out, spoof_nonessential=True, force_phase=True)
if args.filetype == "miriad":
    uv2.write_miriad(args.file_out, clobber=True)
Ejemplo n.º 12
0
def run(input, outfile, verbose, save_all, clobber):
    """Run a full simulation with systematics.
    
    """
    if verbose:
        print("Loading configuration file...")

    # load in config
    with open(input, 'r') as fl:
        yaml_contents = yaml.load(fl.read(), Loader=yaml.FullLoader)

    # figure out whether or not to do BDA
    bda_params = yaml_contents.get("bda", {})
    # make sure bda is installed if the user wants to do BDA
    if bda_params and bda is None:
        raise ImportError("You have defined BDA parameters but do not have "
                          "bda installed. Please install bda to proceed.")

    if verbose:
        print("Checking validity of filing parameters...")

    # extract parameters for saving to disk
    filing_params = yaml_contents.get("filing", {})

    # construct outfile name if not passed from command line
    if outfile is None:
        outfile = os.path.join(filing_params["outdir"],
                               filing_params["outfile_name"])

    # get the filing format
    fmt = filing_params.get("output_format", None)
    assert fmt is not None, \
        "The output file format must be specified in the configuration file " \
        "under the 'filing' section."

    # assume miriad files have the extension "uv"; others are same as name
    fmt_to_ext = {"miriad": "uv", "uvfits": "uvfits", "uvh5": "uvh5"}

    # make sure the output format is supported; only miriad, uvfits, uvh5
    # are currently supported by UVData objects
    supported_fmts = tuple(fmt_to_ext.keys())
    assert fmt in supported_fmts, \
        "UVData objects currently only support writing to the following " \
        "datatypes: {}".format(supported_fmts)

    # add appropriate extension if not specified already, but allow custom ext
    if os.path.splitext(outfile)[1] == '':
        outfile += ".%s" % fmt_to_ext[fmt]

    # add clobber to filing parameters if it's not already in there
    # also choose to clobber if told to do so from command line
    if filing_params.get("clobber", None) is None or clobber:
        filing_params["clobber"] = clobber
    if os.path.exists(outfile) and not filing_params['clobber']:
        print("Nothing to do: %s already exists and clobber=False" % outfile)
        return

    if verbose:
        print("Determining whether to use a default configuration...")

    # determine whether to use season defaults
    defaults = yaml_contents.get("defaults", {})
    if defaults:
        # this assertion is made to keep the configuration file as neat as
        # possible; it is confusing to have a full configuration nested
        # inside another configuration
        assert isinstance(defaults["default_config"], str), \
               "If a default configuration is set with the default_config " \
               "option in the configuration YAML, then it must be specified " \
               "by a string which is either an absolute path to a config " \
               "file compatible with hera_sim.defaults, or one of the season " \
               "configuration keywords."
        hera_sim.defaults.set(defaults["default_config"])

    if verbose:
        print("Constructing Simulator object...")

    # extract instrument parameters
    if isinstance(yaml_contents["telescope"]["array_layout"], str):
        # assume it's an antenna layout csv
        antennas = _parse_layout_csv(
            yaml_contents["telescope"]["array_layout"])
    else:
        # assume it's constructed using antpos and the YAML tag !antpos
        antennas = yaml_contents["telescope"]["array_layout"]
    instrument_params = {"antennas": antennas}
    for parameter in (
            "freq",
            "time",
    ):
        for key, value in yaml_contents[parameter].items():
            instrument_params[key] = value

    sim = hera_sim.Simulator(**instrument_params)

    # for this application, we only want the sky temperature model and
    # beam size; this will need to be updated in the future when the
    # defaults handling is changed, but we'll leave that to the version
    # 1 release
    config_params = {}
    # look for Tsky_mdl, omega_p, and integration_time; extract these
    # note that this may not be an exhaustive list
    for content in yaml_contents.values():
        if "Tsky_mdl" in content.keys():
            config_params["Tsky_mdl"] = content["Tsky_mdl"]
        if "omega_p" in content.keys():
            config_params["omega_p"] = content["omega_p"]
        if "integration_time" in content.keys():
            config_params["inttime"] = content["integration_time"]
    # warn the user if both defaults and configuration parameters specified
    if defaults and config_params:
        warnings.warn("You have chosen to use a default configuration in "
                      "addition to listing configuration parameters. The "
                      "configuration parameters will override any default "
                      "parameters that show up in both places.")
    if config_params:
        hera_sim.defaults.set(config_params)

    if not config_params and not defaults:
        warnings.warn("You have specified neither defaults nor configuration "
                      "parameters. This may result in the simulation erroring "
                      "at some point.")

    if verbose:
        print("Extracting simulation parameters...")
    # extract the simulation parameters from the configuration file
    # the configuration file should only specify any particular parameter once
    # i.e. the same sky temperature model should be used throughout
    sim_params = {}
    sim_details = yaml_contents["simulation"]
    if verbose and save_all:
        print("Running simulation...")
    for component in sim_details["components"]:
        for content in yaml_contents.values():
            if component in content.keys():
                for model, params in content[component].items():
                    if model in sim_details["exclude"]:
                        continue
                    if save_all:
                        # we need to do this piecemeal
                        sim_params = {model: params}
                        # make sure new component is returned
                        sim_params[model]["ret_vis"] = True
                        # make a copy of the Simulator object
                        sim_copy = copy.deepcopy(sim)

                        # write component vis to copy's data array
                        vis = sim.run_sim(**sim_params)[0][1]
                        sim_copy.data.data_array = vis
                        # update the history to only note this component
                        sim_copy.data.history = \
                            sim.data.history.replace(sim_copy.data.history, '')
                        # update the filename
                        base, ext = os.path.splitext(outfile)
                        copy_out = '.'.join((base, model)) + ext
                        # save the component
                        sim_copy.write_data(
                            copy_out,
                            file_type=filing_params["output_format"],
                            **filing_params['kwargs'])
                    else:
                        sim_params[model] = params
            continue

    if verbose and not save_all:
        print("Running simulation...")
    if not save_all:
        sim.run_sim(**sim_params)

    # if the user wants to do BDA, then apply BDA
    if bda_params:
        # convert corr_FoV_angle to an Angle object
        bda_params["corr_FoV_angle"] = Angle(bda_params["corr_FoV_angle"])
        if verbose:
            print("Performing BDA...")
        sim.data = bda_tools.apply_bda(sim.data, **bda_params)

    # save the simulation
    # note that we may want to allow the functionality for the user to choose some
    # kwargs to pass to the write method
    if verbose:
        print("Writing simulation results to disk...")

    # before writing to disk, update the history to note the config file used
    sim.data.history += "\nSimulation from configuration file: {cfg}".format(
        cfg=input)
    sim.write_data(outfile,
                   file_type=filing_params["output_format"],
                   **filing_params["kwargs"])

    if verbose:
        print("Simulation complete.")

    return